1. ภาพรวม
บทช่วยสอนนี้จะสาธิตวิธีการอ่านไฟล์ขนาดใหญ่ใน Java อย่างมีประสิทธิภาพ Java - กลับสู่พื้นฐาน
2. อ่านในหน่วยความจำ
วิธีมาตรฐานในการอ่านบรรทัดไฟล์คือการอ่านในหน่วยความจำ ทั้ง Guava และ ApacheCommonsio มีวิธีการอ่านบรรทัดไฟล์อย่างรวดเร็วดังนี้:
Files.readLines(new File(path), Charsets.UTF_8);
FileUtils.readLines(new File(path));
ปัญหาเกี่ยวกับวิธีนี้คือทุกบรรทัดของไฟล์จะถูกเก็บไว้ในหน่วยความจำและเมื่อไฟล์มีขนาดใหญ่พอมันจะทำให้โปรแกรมส่งข้อยกเว้น outofmemoryError อย่างรวดเร็ว
ตัวอย่างเช่น: อ่านไฟล์ประมาณ 1G:
@TestPublic เป็นโมฆะที่ได้รับฯล
วิธีนี้ใช้หน่วยความจำเพียงเล็กน้อยในตอนแรก: (ใช้หน่วยความจำประมาณ 0MB)
[หลัก] ข้อมูล org.baeldung.java.corejavaiounittest - หน่วยความจำทั้งหมด: 128 MB [หลัก] info org.baeldung.java.corejavaiounittest - หน่วยความจำฟรี: 116 MB
อย่างไรก็ตามเมื่อไฟล์ทั้งหมดถูกอ่านลงในหน่วยความจำในที่สุดเราจะเห็น (ใช้หน่วยความจำประมาณ 2GB):
[Main] Info org.baeldung.java.corejavaiounittest - หน่วยความจำทั้งหมด: 2666 MB [หลัก] info org.baeldung.java.corejavaiounittest - หน่วยความจำฟรี: 490 MB
ซึ่งหมายความว่ากระบวนการนี้ใช้หน่วยความจำประมาณ 2.1GB - เหตุผลนั้นง่าย: ตอนนี้ทุกบรรทัดของไฟล์จะถูกเก็บไว้ในหน่วยความจำ
การใส่เนื้อหาทั้งหมดของไฟล์ในหน่วยความจำจะหมดลงอย่างรวดเร็วจากหน่วยความจำที่มีอยู่ - ไม่ว่าหน่วยความจำที่มีอยู่จริงจะมีขนาดใหญ่เพียงใด
นอกจากนี้เรามักจะไม่จำเป็นต้องใส่ไฟล์ทั้งหมดลงในหน่วยความจำในครั้งเดียว - แต่เราเพียงแค่ต้องสำรวจแต่ละบรรทัดของไฟล์จากนั้นทำการประมวลผลที่สอดคล้องกันและโยนมันออกไปหลังจากการประมวลผล นั่นคือสิ่งที่เรากำลังจะทำ - วนซ้ำแถวแทนที่จะใส่แถวทั้งหมดไว้ในหน่วยความจำ
3. สตรีมไฟล์
ตอนนี้ลองดูที่โซลูชันนี้ - เราจะใช้คลาส java.util.scanner เพื่อสแกนเนื้อหาของไฟล์และอ่านทีละบรรทัดอย่างต่อเนื่อง:
FileInputStream inputStream = null; Scanner sc = null; ลอง {inputStream = new FileInputStream (พา ธ ); SC = ใหม่สแกนเนอร์ (อินพุตสตรีม "UTF-8"); ในขณะที่ (sc.hasnextline ()) {สตริงบรรทัด = sc.nextline (); // system.out.println (บรรทัด); } // โปรดทราบว่าสแกนเนอร์ระงับข้อยกเว้นถ้า (sc.ioexception ()! = null) {โยน sc.ioexception (); }} ในที่สุด {ถ้า (inputStream! = null) {inputStream.close (); } if (sc! = null) {sc.close (); -โซลูชันนี้จะสำรวจทุกบรรทัดในไฟล์ - อนุญาตให้แต่ละบรรทัดได้รับการประมวลผลโดยไม่ต้องอ้างอิงถึงมัน อย่างไรก็ตามพวกเขาไม่ได้เก็บไว้ในหน่วยความจำ: (ประมาณ 150MB ของหน่วยความจำถูกบริโภค)
[หลัก] infoorg.baeldung.java.corejavaiounittest-totalmemory: 763MB
[หลัก] infoorg.baeldung.java.corejavaiounittest-freememory: 605MB
4. สตรีม ApacheCommonsio
นอกจากนี้คุณยังสามารถใช้ไลบรารี Commonsio เพื่อใช้งานโดยใช้ LineIterator ที่กำหนดเองโดยไลบรารี:
LINEITERATOR IT = FILEUTILS.LINITERATOR (TheFile, "UTF-8"); ลอง {ในขณะที่ (it.hasnext ()) {String line = it.nextline (); // ทำอะไรบางอย่างกับ Line}} ในที่สุด {lineIterator.closequietly (มัน);}เนื่องจากไฟล์ทั้งหมดไม่ได้ถูกเก็บไว้ในหน่วยความจำสิ่งนี้นำไปสู่การใช้หน่วยความจำที่ค่อนข้างอนุรักษ์นิยม: (ประมาณ 150MB ของหน่วยความจำใช้)
[Main] Infoo.b.java.corejavaiointegrationtest-totalmemory: 752mb
[Main] Infoo.b.java.corejavaiointegrationtest-FreeMemory: 564MB
5. บทสรุป
บทความสั้น ๆ นี้อธิบายถึงวิธีการประมวลผลไฟล์ขนาดใหญ่โดยไม่ต้องอ่านซ้ำและไม่มีหน่วยความจำ - ซึ่งเป็นโซลูชันที่มีประโยชน์สำหรับการประมวลผลไฟล์ขนาดใหญ่
ตัวอย่างทั้งหมดเหล่านี้ถูกนำไปใช้และตัวอย่างรหัสที่มีอยู่ในโครงการ GitHub ของฉัน - นี่คือโครงการที่ใช้ Eclipse ดังนั้นควรนำเข้าและทำงานได้ง่าย
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้เกี่ยวกับการอ่านไฟล์ขนาดใหญ่ Java อย่างมีประสิทธิภาพ ฉันหวังว่ามันจะเป็นประโยชน์กับทุกคน เพื่อนที่สนใจสามารถอ้างถึงหัวข้ออื่น ๆ ที่เกี่ยวข้องในเว็บไซต์นี้ต่อไป หากมีข้อบกพร่องใด ๆ โปรดฝากข้อความไว้เพื่อชี้ให้เห็น ขอบคุณเพื่อนที่ให้การสนับสนุนเว็บไซต์นี้!