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.