Hogyan lehet hatékonyan elolvasni egy nagy fájlt a Java-val

1. Áttekintés

Ez az oktatóanyag megmutatja hogyan olvassuk el az összes sort egy nagy fájlból a Java-ban hatékony módon.

Ez a cikk a „Java - Vissza az alapokhoz”Bemutató itt a Baeldung-on.

2. Memóriában olvasás

A fájl sorainak szabványos olvasási módja a memóriában van - mind a Guava, mind az Apache Commons IO gyors módot kínál erre:

Files.readLines (új File (elérési út), Charsets.UTF_8);
FileUtils.readLines (új fájl (elérési út));

Ezzel a megközelítéssel az a probléma, hogy az összes fájlsor memóriában marad - ami gyorsan vezet OutOfMemoryError ha a Fájl elég nagy.

Például - ~ 1Gb-os fájl olvasása:

@Test public void givenUsingGuava_whenIteratingAFile_thenWorks () dobja az IOException {String path = ... Files.readLines (új File (elérési út), Charsets.UTF_8); }

Ez egy kis memóriafelhasználással kezdődik: (~ 0 Mb fogyasztva)

[main] INFO org.baeldung.java.CoreJavaIoUnitTest - Teljes memória: 128 Mb [main] INFO org.baeldung.java.CoreJavaIoUnitTest - Szabad memória: 116 Mb

Azonban, a teljes fájl feldolgozása után, a végén van: (~ 2 Gb elfogyasztva)

[main] INFO org.baeldung.java.CoreJavaIoUnitTest - Teljes memória: 2666 Mb [main] INFO org.baeldung.java.CoreJavaIoUnitTest - Szabad memória: 490 Mb

Ami azt jelenti, hogy a folyamat körülbelül 2,1 Gb memóriát emészt fel - az ok egyszerű -, a fájl sorai most a memóriában vannak tárolva.

Ekkor nyilvánvalónak kell lennie A fájl tartalmának memóriában tartása gyorsan kimeríti a rendelkezésre álló memóriát - függetlenül attól, hogy ez valójában mennyi.

Mi több, általában nincs szükségünk a fájl összes sorára a memóriában egyszerre - ehelyett csak át kell tudnunk ismételni mindegyiket, el kell végeznünk valamilyen feldolgozást és kidobnunk. Tehát pontosan ezt fogjuk tenni - iteráljuk végig a sorokat anélkül, hogy mindet a memóriában tartanánk.

3. Átfolyás a fájlon keresztül

Most nézzünk meg egy megoldást - a java.util.Scan a fájl tartalmának végigfutása és a sorok soros lekérése egyesével:

FileInputStream inputStream = null; Szkenner sc = null; próbáld ki az {inputStream = new FileInputStream (elérési út); sc = új szkenner (inputStream, "UTF-8"); while (sc.hasNextLine ()) {Karaktersor = sc.nextLine (); // System.out.println (sor); } // vegye figyelembe, hogy a Szkenner elnyomja a kivételeket, ha (sc.ioException ()! = null) {dobja sc.ioException (); }} végül {if (inputStream! = null) {inputStream.close (); } if (sc! = null) {sc.close (); }}

Ez a megoldás a fájl összes sorát végig fogja hajtani - lehetővé téve az egyes sorok feldolgozását - anélkül, hogy hivatkozásokat tartana rájuk - és végül anélkül, hogy emlékezetben tartanák őket: (~ 150 Mb elfogyasztva)

[main] INFO org.baeldung.java.CoreJavaIoUnitTest - Teljes memória: 763 Mb [main] INFO org.baeldung.java.CoreJavaIoUnitTest - Szabad memória: 605 Mb

Streaming With Apache Commons IO

Ugyanez érhető el a Commons IO könyvtár használatával is a szokás LineIterator a könyvtár biztosítja:

LineIterator it = FileUtils.lineIterator (theFile, "UTF-8"); próbáld meg a {while (it.hasNext ()) {String line = it.nextLine (); // csinálj valamit a sorral}} végül {LineIterator.closeQuietly (it); }

Mivel az egész fájl nincs teljesen a memóriában - ez azt is eredményezi elég konzervatív memóriafogyasztási számok: (~ 150 Mb elfogyasztva)

[main] INFO o.b.java.CoreJavaIoIntegrationTest - Teljes memória: 752 Mb [main] INFO o.b.java.CoreJavaIoIntegrationTest - Szabad memória: 564 Mb

5. Következtetés

Ez a gyors cikk bemutatja, hogyan kell feldolgozza a sorokat egy nagy fájlban iteráció nélkül, a rendelkezésre álló memória kimerítése nélkül - ami nagyon hasznosnak bizonyul, ha ilyen nagy fájlokkal dolgozik.

Mindezen példák és kódrészletek megvalósítása megtalálható a GitHub projektünkben - ez egy Maven-alapú projekt, ezért könnyen importálhatónak és futtathatónak kell lennie.


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