คำนำ
ในบทความก่อนหน้านี้เราได้แนะนำเนื้อหาที่เกี่ยวข้องในกรอบการสตรีมไบต์ไฟล์ของ Java ในขณะที่บทความของเราจะมุ่งเน้นไปที่เนื้อหาที่เกี่ยวข้องของการสตรีมอักขระไฟล์
ก่อนอื่นควรชัดเจนว่าไฟล์การประมวลผลสตรีมไบต์จะขึ้นอยู่กับไบต์ในขณะที่ไฟล์การประมวลผลสตรีมอักขระจะขึ้นอยู่กับอักขระเป็นหน่วยพื้นฐาน
แต่ในความเป็นจริงสาระสำคัญของการดำเนินการสตรีมอักขระคือการห่อหุ้มของสองกระบวนการของ "การดำเนินการสตรีมไบต์" + "การเข้ารหัส" คุณคิดอย่างนั้นไหม? ไม่ว่าคุณจะเขียนอักขระลงในไฟล์คุณต้องเข้ารหัสอักขระลงในไบนารีแล้วเขียนลงในไฟล์ในไบต์เป็นหน่วยพื้นฐานหรือคุณอ่านอักขระไปยังหน่วยความจำคุณต้องอ่านเป็นไบต์เป็นหน่วยพื้นฐานแล้วแปลงเป็นตัวละคร
สิ่งสำคัญคือต้องเข้าใจสิ่งนี้ซึ่งจะกำหนดความเข้าใจโดยรวมของคุณเกี่ยวกับสตรีมตัวละคร ลองมาดูการออกแบบ API ที่เกี่ยวข้องด้วยกัน
ผู้อ่าน/นักเขียนชั้นเรียนฐาน
ก่อนที่จะเรียนรู้คลาสพื้นฐานของสตรีมตัวละครอย่างเป็นทางการเราจำเป็นต้องรู้ว่าตัวละครเป็นตัวแทนใน Java อย่างไร
ก่อนอื่นการเข้ารหัสอักขระเริ่มต้นใน Java คือ: UTF-8 และเรารู้ว่าอักขระที่เข้ารหัส UTF-8 จะถูกเก็บไว้โดยใช้ 1 ถึง 4 ไบต์และอักขระที่ใช้กันทั่วไปจะใช้ไบต์น้อยลง
ประเภทถ่านถูกกำหนดให้เป็นสองขนาดไบต์นั่นคือสำหรับตัวละครทั่วไปถ่านสามารถเก็บตัวละครได้ แต่สำหรับชุดอักขระเสริมบางชุดตัวอักษรสองตัวมักจะใช้เพื่อแสดงถึงตัวละคร
Reader เป็นคลาสพื้นฐานสำหรับการอ่านสตรีมอักขระและให้การดำเนินการอ่านอักขระพื้นฐานที่สุด ลองมาดูกัน
มาดูตัวสร้างก่อน:
การล็อควัตถุที่ได้รับการป้องกัน; protected reader () {this.lock = this;} reader ที่ได้รับการป้องกัน (ล็อควัตถุ) {ถ้า (ล็อค == null) {โยน nullpointerexception ใหม่ (); } this.lock = lock;}ผู้อ่านเป็นคลาสที่เป็นนามธรรมดังนั้นไม่ต้องสงสัยเลยว่าตัวสร้างเหล่านี้จะถูกเรียกไปยังคลาสย่อยและใช้ในการเริ่มต้นวัตถุล็อคล็อคซึ่งเราจะอธิบายรายละเอียดในภายหลัง
public int read () พ่น ioexception {char cb [] = char ใหม่ [1]; if (อ่าน (cb, 0, 1) == -1) return -1; else return cb [0];} public int read (char cbuf []) โยน ioexception {return read (cbuf, 0, cbuf.length);} บทคัดย่อสาธารณะอ่าน (ถ่าน cbuf []การดำเนินการอ่านตัวละครพื้นฐานอยู่ที่นี่ทั้งหมด วิธีแรกใช้ในการอ่านอักขระ หากได้รับการอ่านจนถึงตอนท้ายของไฟล์มันจะส่งคืน -1 ได้รับเช่นเดียวกันกับ Int เป็นประเภทค่าส่งคืนทำไมไม่ใช้ถ่าน? เหตุผลก็เหมือนกันทั้งหมดเนื่องจากความไม่แน่นอนของการตีความค่า -1
วิธีที่สองคล้ายกับวิธีที่สามการอ่านอักขระที่มีความยาวที่ระบุจากไฟล์และวางไว้ในอาร์เรย์เป้าหมาย วิธีที่สามคือวิธีนามธรรมซึ่งจำเป็นต้องใช้โดยคลาสย่อยในขณะที่วิธีที่สองจะขึ้นอยู่กับมัน
มีวิธีอื่น ๆ ที่คล้ายกัน:
วิธีการเหล่านี้เป็นที่รู้จักกันดีและโดยทั่วไปคล้ายกับอินพุตของเราและพวกเขาไม่มีการใช้งานหลัก ฉันจะไม่เข้าไปดูรายละเอียดที่นี่คุณสามารถรู้ได้ว่ามีอะไรอยู่ข้างใน
Writer เป็นสตรีมอักขระที่เขียนซึ่งใช้ในการเขียนอักขระอย่างน้อยหนึ่งตัวลงในไฟล์ แน่นอนวิธีการเขียนที่เฉพาะเจาะจงยังคงเป็นวิธีที่เป็นนามธรรมและจะถูกนำไปใช้โดยคลาสย่อยดังนั้นเราจะไม่ทำซ้ำที่นี่
อะแดปเตอร์ inpuststramreader/outputstreamwriter
สตรีมอักขระอะแดปเตอร์ที่สืบทอดมาจากตัวอ่านชั้นเรียนหรือนักเขียนซึ่งเป็นสมาชิกที่สำคัญมากของระบบสตรีมอักขระ ฟังก์ชั่นหลักคือการแปลงสตรีมไบต์เป็นสตรีมอักขระ ก่อนอื่นลองใช้อะแดปเตอร์อ่านเป็นตัวอย่าง
ก่อนอื่นสมาชิกหลักของมัน:
StreamDecoder SD SD;
StreamDecoder เป็นตัวถอดรหัสที่ใช้ในการแปลงการดำเนินการต่าง ๆ ของไบต์เป็นการดำเนินการที่สอดคล้องกันของอักขระ เราจะพูดถึงมันอย่างต่อเนื่องในการแนะนำครั้งต่อไปและเราจะไม่อธิบายอย่างสม่ำเสมอที่นี่
จากนั้นก็มีตัวสร้าง:
Public InputStreamReader (InputStream ใน) {super (in); ลอง {sd = streamdecoder.forinputstreamreader (ใน, นี่, (สตริง) null); } catch (unsupportencodingexception e) {โยนข้อผิดพลาดใหม่ (e); }} Public InputStreamReader (inputStream ใน, charsetName สตริง) พ่น unsupportencodexception {super (in); if (charsetName == null) โยน nullpointerexception ใหม่ ("charsetName"); SD = StreamDecoder.ForInputStreamReader (ใน, นี่, charsetName);}วัตถุประสงค์ของตัวสร้างทั้งสองนี้คือการเริ่มต้นถอดรหัสนี้ วิธีการ forinputStreamReader เรียกว่า แต่พารามิเตอร์แตกต่างกัน มาดูการใช้วิธีนี้กันเถอะ:
นี่คือรูปแบบโรงงานคงที่ทั่วไป ไม่มีอะไรจะพูดเกี่ยวกับพารามิเตอร์สามตัว VAR0 และ VAR1 ซึ่งเป็นตัวแทนของอินสแตนซ์ BYTE สตรีมและอินสแตนซ์อะแดปเตอร์ตามลำดับ
พารามิเตอร์ VAR2 แสดงถึงชื่อการเข้ารหัสอักขระ หากเป็นโมฆะการเข้ารหัสอักขระเริ่มต้นของระบบจะถูกใช้: UTF-8
ในที่สุดเราก็สามารถรับอินสแตนซ์ของตัวถอดรหัสได้
วิธีการเกือบทั้งหมดที่แนะนำต่อไปจะถูกนำไปใช้โดยอาศัยตัวถอดรหัสนี้
Public String getenCoding () {return sd.getencoding ();} public int read () พ่น ioexception {return sd.read ();} int public int อ่าน (ถ่าน cbuf [], int offset, ความยาว int) {return sd.read (cbuf, Offset, ความยาว);รหัสการใช้งานของวิธีการที่เกี่ยวข้องในตัวถอดรหัสยังคงค่อนข้างซับซ้อน เราจะไม่ทำการวิจัยเชิงลึกที่นี่ แต่แนวคิดการใช้งานทั่วไปคือ: กระบวนการของ "การอ่านกระแสไบต์ + การถอดรหัส"
แน่นอนว่าจะต้องมีอินสแตนซ์ StreamEncoder ตรงข้ามใน OutputStreamWriter สำหรับการเข้ารหัสอักขระ
นอกเหนือจากนี้ส่วนที่เหลือของการดำเนินการไม่แตกต่างกันไม่ว่าจะเขียนไปยังไฟล์ผ่านอาร์เรย์อักขระที่เขียนลงในไฟล์ผ่านสตริงหรือเขียนลงในไฟล์ผ่าน 16 บิตที่ต่ำกว่าของ int
สตรีมอักขระสตรีม filereader/นักเขียน
สตรีมอักขระของไฟล์สามารถกล่าวได้ว่าง่ายมาก ไม่มีวิธีอื่นใดนอกจากตัวสร้างและขึ้นอยู่กับสตรีมไฟล์ไบต์ทั้งหมด
ลองใช้ Filereader เป็นตัวอย่าง
filereader สืบทอดมาจาก inputstreamreader และมีเพียงสามตัวสร้างต่อไปนี้: public filereader (String filename) พ่น filenotfoundException {super (fileInputStream ใหม่ (ชื่อไฟล์));} public filereader (ไฟล์ไฟล์) FileInputStream (FD));}ในทางทฤษฎีสตรีมอักขระทั้งหมดควรขึ้นอยู่กับอะแดปเตอร์ของเราเพราะมีเพียงการแปลงตัวละครต่อไบต์ไม่ว่าคุณจะเขียนหรืออ่านมันจะแยกออกจากมันออกไป
filereader ของเราไม่ขยายวิธีการใด ๆ ของตัวเอง วิธีการใช้งานอักขระที่ใช้ล่วงหน้าในคลาสพาเรนต์อินพุทสตรีมรีดเนอร์นั้นเพียงพอสำหรับเขา เขาต้องผ่านอินสแตนซ์ของไบต์สตรีมที่สอดคล้องกันเท่านั้น
เช่นเดียวกับ FileWriter ฉันจะไม่เข้าไปดูรายละเอียดที่นี่
สตรีมอักขระอาร์เรย์ chararrayreader/นักเขียน
อาร์เรย์อักขระและสตรีมอาร์เรย์ไบต์มีความคล้ายคลึงกันทั้งสำหรับการแก้สถานการณ์ที่มีขนาดไฟล์ที่ไม่แน่นอนและต้องอ่านเนื้อหาจำนวนมาก
เนื่องจากพวกเขามีกลไกการขยายตัวแบบไดนามิกภายในพวกเขาไม่เพียง แต่สามารถรองรับไฟล์เป้าหมายได้ แต่ยังควบคุมขนาดอาร์เรย์เพื่อไม่ให้จัดสรรหน่วยความจำมากเกินไปและเสียพื้นที่หน่วยความจำจำนวนมาก
นำ ChararrayReader เป็นตัวอย่าง
ได้รับการป้องกันถ่าน buf []; chararrayreader สาธารณะ (char buf []) {this.buf = buf; this.pos = 0; this.count = buf.length;} public chararrayreader (char buf [], int offset, ความยาว int) {// .. }ภารกิจหลักของตัวสร้างคือการเริ่มต้นอาร์เรย์อักขระลงในแอตทริบิวต์ BUF ภายใน การดำเนินการอ่านที่ตามมาทั้งหมดในอินสแตนซ์สตรีมอาร์เรย์อักขระจะขึ้นอยู่กับอาร์เรย์อักขระ BUF
เกี่ยวกับวิธีการอื่น ๆ ของ ChararrayReader และ ChararrayWriter ฉันจะไม่ทำซ้ำที่นี่ซึ่งโดยทั่วไปคล้ายกับสตรีมอาร์เรย์ BYTE ในบทความก่อนหน้า
นอกจากนี้ยังมี StringReader และ StringWriter ที่เกี่ยวข้อง ในความเป็นจริงมันเป็นหลักเช่นเดียวกับสตรีมอาร์เรย์ตัวละคร ท้ายที่สุดสาระสำคัญของสตริงคืออาร์เรย์ถ่าน
BufferedReader/Writer
ในทำนองเดียวกัน BufferedReader/Writer เป็นกระแสบัฟเฟอร์และยังเป็นสตรีมมัณฑนากรใช้เพื่อให้ฟังก์ชั่นบัฟเฟอร์ โดยทั่วไปคล้ายกับสตรีมบัฟเฟอร์ไบต์ของเราเรามาแนะนำสั้น ๆ ที่นี่
ผู้อ่านส่วนตัวใน; ถ่านส่วนตัว CB []; int private int defaultCharBuffersize = 8192; bufferedReader สาธารณะ (ผู้อ่าน, int sz) {.. } public BufferedReader (ผู้อ่านใน) {สิ่งนี้ (ใน, defaultcharbuffersize);}CB เป็นอาร์เรย์อักขระที่แคชอักขระบางตัวอ่านจากสตรีมไฟล์ คุณสามารถเริ่มต้นความยาวของอาร์เรย์นี้ในตัวสร้างมิฉะนั้นจะใช้ค่าเริ่มต้นที่ 8192
Public Int Read () พ่น IOException {.. } INT Public Int Read (Char Cbuf [], int ปิด, int len) {... }เกี่ยวกับการอ่านมันขึ้นอยู่กับวิธีการอ่านของแอตทริบิวต์สมาชิกในฐานะประเภทผู้อ่านในวิธีการอ่านมักจะอ่านของอินพุทสตรีมที่พึ่งพาภายใน
ดังนั้นสตรีมอักขระเกือบทั้งหมดไม่สามารถแยกออกจากอินสแตนซ์สตรีมไบต์
ฉันจะไม่ทำซ้ำที่นี่เกี่ยวกับ BufferedWriter มันคล้ายกันโดยทั่วไปยกเว้นว่ามีการอ่านและอีกอันกำลังเขียนและมันหมุนรอบตัวละครภายในอาร์เรย์
สตรีมการพิมพ์มาตรฐาน
มีสองประเภทหลักของสตรีมการพิมพ์ PrintStream และ Printwriter อดีตคือสตรีมไบต์และหลังเป็นสตรีมตัวละคร
สตรีมทั้งสองนี้ได้รับการพิจารณาให้รวมสตรีมภายใต้หมวดหมู่ของพวกเขา มีวิธีการห่อหุ้มภายในที่หลากหลาย แต่การใช้งานก็ค่อนข้างซับซ้อน ก่อนอื่นดูที่สตรีม PrintStream Byte:
มีตัวสร้างหลักหลายตัว:
เห็นได้ชัดว่าตัวสร้างที่เรียบง่ายจะพึ่งพาตัวสร้างที่ซับซ้อนซึ่งถือว่าเป็น "กิจวัตรเก่า" สำหรับการออกแบบ JDK สิ่งที่แยกความแตกต่างจากสตรีมไบต์อื่น ๆ คือ PrintStream ให้บริการ Autoflush Autoflush ที่ระบุว่าจะรีเฟรชแคชโดยอัตโนมัติหรือไม่
ถัดไปคือวิธีการเขียนของ printstream:
นอกจากนี้ PrintStream ยังสรุปวิธีการพิมพ์จำนวนมากและเขียนเนื้อหาประเภทต่างๆลงในไฟล์เช่น:
แน่นอนว่าวิธีการเหล่านี้ไม่ได้เขียนไบนารีตัวเลขลงในไฟล์ แต่เพียงแค่เขียนสตริงที่เกี่ยวข้องลงในไฟล์เช่น:
พิมพ์ (123);
ไฟล์สุดท้ายไม่ใช่คำสั่งไบนารีที่สอดคล้องกับ 123 แต่เพียงแค่สตริง 123 ซึ่งเป็นสตรีมการพิมพ์
สตรีมอักขระบัฟเฟอร์ที่ใช้โดย PrintStream ใช้การดำเนินการพิมพ์ทั้งหมด หากระบุการรีเฟรชอัตโนมัติบัฟเฟอร์จะได้รับการรีเฟรชโดยอัตโนมัติเมื่อพบสัญลักษณ์ใหม่ "/n"
ดังนั้น PrintStream จึงรวมวิธีการเอาต์พุตทั้งหมดในสตรีมไบต์และสตรีมอักขระซึ่งใช้วิธีการเขียนสำหรับการดำเนินการสตรีมไบต์และวิธีการพิมพ์ใช้สำหรับการดำเนินการสตรีมอักขระซึ่งจำเป็นต้องชี้แจง
สำหรับ PrintWriter มันเป็นสตรีมอักขระเต็มรูปแบบที่ทำงานกับอักขระอย่างสมบูรณ์ ไม่ว่าจะเป็นวิธีการเขียนหรือวิธีการพิมพ์มันเป็นการดำเนินการสตรีมอักขระ
เพื่อสรุปเราใช้เวลาสามบทความที่อธิบายสตรีมไบต์และการดำเนินการสตรีมตัวละครใน Java ไบต์สตรีมการส่งข้อมูลที่สมบูรณ์ระหว่างดิสก์และหน่วยความจำตามไบต์ หนึ่งทั่วไปคือสตรีมอักขระไฟล์และการใช้งานของพวกเขาเป็นวิธีการในท้องถิ่นทั้งหมด ด้วยความสามารถในการถ่ายโอนไบต์ขั้นพื้นฐานเรายังสามารถปรับปรุงประสิทธิภาพผ่านการบัฟเฟอร์
การใช้งานพื้นฐานที่สุดของสตรีมอักขระคือ inputStreamReader และ OutputStreamWriter ในทางทฤษฎีพวกเขาสามารถดำเนินการสตรีมอักขระพื้นฐานได้แล้ว แต่พวกเขาก็ จำกัด เฉพาะการดำเนินการขั้นพื้นฐานที่สุดเท่านั้น สิ่งที่จำเป็นในการสร้างอินสแตนซ์ของพวกเขาคือ "อินสแตนซ์สตรีมไบต์" + "รูปแบบการเข้ารหัส"
ดังนั้นความสัมพันธ์ระหว่างสตรีมอักขระและสตรีมไบต์จึงเหมือนกับสมการข้างต้น ขั้นตอนที่จำเป็นสำหรับการเขียนอักขระลงในไฟล์ดิสก์คือการเข้ารหัสอักขระในรูปแบบการเข้ารหัสที่ระบุจากนั้นใช้สตรีมไบต์เพื่อเขียนไบนารีอักขระที่เข้ารหัสไปยังไฟล์ การดำเนินการอ่านเป็นสิ่งที่ตรงกันข้าม
รหัสรูปภาพและไฟล์ทั้งหมดในบทความจะถูกเก็บไว้ในคลาวด์บน GitHub ของฉัน:
(https://github.com/singleyam/overview_java)
คุณยังสามารถเลือกที่จะดาวน์โหลดในพื้นที่
สรุป
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่าเนื้อหาของบทความนี้จะมีค่าอ้างอิงบางอย่างสำหรับการศึกษาหรือที่ทำงานของทุกคน หากคุณมีคำถามใด ๆ คุณสามารถฝากข้อความไว้เพื่อสื่อสาร ขอบคุณสำหรับการสนับสนุน Wulin.com