כיצד לקרוא קובץ גדול ביעילות עם Java

1. סקירה כללית

הדרכה זו תוצג כיצד לקרוא את כל השורות מקובץ גדול בג'אווה בצורה יעילה.

מאמר זה הוא חלק מה- "ג'אווה - חזרה לבסיסי”הדרכה כאן על באלדונג.

2. קריאה בזיכרון

הדרך הסטנדרטית לקריאת שורות הקובץ היא בזיכרון - הן גויאבה והן Apache Commons IO מספקים דרך מהירה לעשות בדיוק את זה:

Files.readLines (קובץ חדש (נתיב), Charsets.UTF_8);
FileUtils.readLines (קובץ חדש (נתיב));

הבעיה בגישה זו היא שכל שורות הקבצים נשמרות בזיכרון - מה שיוביל במהירות OutOfMemoryError אם הקובץ גדול מספיק.

לדוגמה - קריאת קובץ ~ 1Gb:

@Test הציבור בטל givenUsingGuava_whenIteratingAFile_thenWorks () זורק IOException {String path = ... Files.readLines (קובץ חדש (path), Charsets.UTF_8); }

זה מתחיל עם צריכת כמות קטנה של זיכרון: (~ 0 Mb נצרך)

[main] INFO org.baeldung.java.CoreJavaIoUnitTest - זיכרון כולל: 128 Mb [main] INFO org.baeldung.java.CoreJavaIoUnitTest - זיכרון פנוי: 116 Mb

למרות זאת, לאחר עיבוד הקובץ המלא, יש לנו בסוף: (~ 2 GB נצרך)

[main] INFO org.baeldung.java.CoreJavaIoUnitTest - סך כל הזיכרון: 2666 Mb [main] INFO org.baeldung.java.CoreJavaIoUnitTest - זיכרון פנוי: 490 Mb

מה שאומר שכ -2.1 גיגה-בייט של זיכרון נצרכים בתהליך - הסיבה היא פשוטה - שורות הקובץ מאוחסנות כעת בזיכרון.

זה צריך להיות ברור מאליו שמירת הזיכרון של תוכן הקובץ תמצה במהירות את הזיכרון הזמין - ללא קשר לכמות שזה באמת.

מה עוד, בדרך כלל איננו זקוקים לכל שורות הקובץ בזיכרון בבת אחת במקום זאת, אנחנו רק צריכים להיות מסוגלים לחזור דרך כל אחד מהם, לעשות קצת עיבוד ולזרוק אותו. אז זה בדיוק מה שאנחנו הולכים לעשות - לחזור על הקווים מבלי להחזיק את כולם בזיכרון.

3. הזרמה דרך הקובץ

בואו נסתכל עכשיו על פיתרון - נשתמש ב- java.util.Scanner להעביר את תוכן הקובץ ולאחזר שורות סדרתי, אחת אחת:

FileInputStream inputStream = null; סורק sc = null; נסה {inputStream = FileInputStream חדש (נתיב); sc = סורק חדש (inputStream, "UTF-8"); בעוד (sc.hasNextLine ()) {קו מחרוזת = sc.nextLine (); // System.out.println (קו); } // שים לב שהסורק מדכא חריגים אם (sc.ioException ()! = null) {זרוק sc.ioException (); }} סוף סוף {if (inputStream! = null) {inputStream.close (); } אם (sc! = null) {sc.close (); }}

פתרון זה יחזור על כל השורות בקובץ - יאפשר עיבוד של כל שורה - מבלי לשמור על הפניות אליהם - ולסיכום, בלי לשמור אותם בזיכרון: (~ 150 Mb נצרך)

[main] INFO org.baeldung.java.CoreJavaIoUnitTest - סה"כ זיכרון: 763 Mb [main] INFO org.baeldung.java.CoreJavaIoUnitTest - זיכרון פנוי: 605 Mb

4. סטרימינג עם IO של Apache Commons

ניתן להשיג את אותו הדבר באמצעות ספריית IO של Commons גם באמצעות שימוש המנהג LineIterator המסופק על ידי הספרייה:

LineIterator it = FileUtils.lineIterator (theFile, "UTF-8"); נסה {while (it.hasNext ()) {קו מחרוזת = it.nextLine (); // לעשות משהו עם קו}} סוף סוף {LineIterator.closeQuietly (it); }

מכיוון שהקובץ כולו אינו בזיכרון מלא - זה גם יביא ל מספרי צריכת זיכרון די שמרניים: (~ 150 Mb נצרך)

[main] INFO o.b.java.CoreJavaIoIntegrationTest - זיכרון כולל: 752 Mb [main] INFO o.b.java.CoreJavaIoIntegrationTest - זיכרון פנוי: 564 Mb

5. מסקנה

מאמר מהיר זה מראה כיצד לעבד שורות בקובץ גדול ללא איטרטיבי, מבלי למצות את הזיכרון הזמין - מה שמסתייע מאוד בעבודה עם קבצים גדולים אלה.

יישום כל הדוגמאות וקטעי הקוד ניתן למצוא בפרויקט GitHub שלנו - זהו פרויקט מבוסס Maven, כך שיהיה קל לייבא ולהפעיל אותו כפי שהוא.


$config[zx-auto] not found$config[zx-overlay] not found