Ako efektívne čítať veľké súbory s programom Java

1. Prehľad

Tento tutoriál sa ukáže ako čítať všetky riadky z veľkého súboru v Jave efektívnym spôsobom.

Tento článok je súčasťou „Java - späť na základné”Návod tu na Baeldungu.

2. Čítanie v pamäti

Štandardný spôsob čítania riadkov súboru je v pamäti - Guava aj Apache Commons IO poskytujú rýchly spôsob, ako to urobiť:

Files.readLines (nový súbor (cesta), charsety.UTF_8);
FileUtils.readLines (nový súbor (cesta));

Problém tohto prístupu spočíva v tom, že všetky riadky súborov sú uložené v pamäti - čo k nej rýchlo povedie OutOfMemoryError ak je Súbor dostatočne veľký.

Napríklad - čítanie súboru ~ 1 GB:

@Test public void givenUsingGuava_whenIteratingAFile_thenWorks () hodí IOException {reťazcová cesta = ... Files.readLines (nový súbor (cesta), Charsets.UTF_8); }

Začína sa to tým, že sa spotrebuje malé množstvo pamäte: (Spotrebovaná ~ 0 Mb)

[hlavná] INFO org.baeldung.java.CoreJavaIoUnitTest - celková pamäť: 128 Mb [hlavná] INFO org.baeldung.java.CoreJavaIoUnitTest - voľná pamäť: 116 Mb

Avšak po spracovaní celého súboru, máme na konci: (Spotrebované ~ 2 GB)

[hlavná] INFO org.baeldung.java.CoreJavaIoUnitTest - celková pamäť: 2666 Mb [hlavná] INFO org.baeldung.java.CoreJavaIoUnitTest - voľná pamäť: 490 Mb

Čo znamená, že proces spotrebuje asi 2,1 Gb pamäte - dôvod je jednoduchý - riadky súboru sa teraz ukladajú do pamäte.

V tomto bode by malo byť zrejmé, že uchovanie v pamäti obsah súboru rýchlo vyčerpá dostupnú pamäť - bez ohľadu na to, koľko to v skutočnosti je.

Čo je viac, obyčajne nepotrebujeme všetky riadky v súbore v pamäti naraz - namiesto toho musíme byť schopní iterovať každý z nich, urobiť nejaké spracovanie a vyhodiť to. Takže to je presne to, čo urobíme - iterujeme riadkami bez toho, aby sme si ich všetky pamätali.

3. Streamovanie prostredníctvom súboru

Poďme sa teraz pozrieť na riešenie - použijeme a java.util.Scanner spustiť obsah súboru a postupne načítať riadky:

FileInputStream inputStream = null; Skener sc = null; skúsiť {inputStream = nový FileInputStream (cesta); sc = nový skener (inputStream, "UTF-8"); while (sc.hasNextLine ()) {String line = sc.nextLine (); // System.out.println (riadok); } // všimnite si, že Scanner potláča výnimky if (sc.ioException ()! = null) {throw sc.ioException (); }} nakoniec {if (inputStream! = null) {inputStream.close (); } if (sc! = null) {sc.close (); }}

Toto riešenie bude iterovať cez všetky riadky v súbore - čo umožní spracovanie každého riadku - bez uchovania odkazov na ne - a na záver bez toho, aby si ich uchovali v pamäti: (Spotrebovaných ~ 150 Mb)

[hlavná] INFO org.baeldung.java.CoreJavaIoUnitTest - celková pamäť: 763 Mb [hlavná] INFO org.baeldung.java.CoreJavaIoUnitTest - voľná pamäť: 605 Mb

4. Streamovanie pomocou Apache Commons IO

To isté možno dosiahnuť aj pomocou knižnice Commons IO pomocou zvyk LineIterator poskytuje knižnica:

LineIterator it = FileUtils.lineIterator (theFile, "UTF-8"); try {while (it.hasNext ()) {String line = it.nextLine (); // urob niečo s line}} konečne {LineIterator.closeQuietly (it); }

Pretože celý súbor nie je úplne v pamäti - bude to mať za následok tiež dosť konzervatívne čísla spotreby pamäte: (Spotrebovaných ~ 150 Mb)

[hlavný] INFO o.b.java.CoreJavaIoIntegrationTest - celková pamäť: 752 Mb [hlavný] INFO o.b.java.CoreJavaIoIntegrationTest - voľná pamäť: 564 Mb

5. Záver

Tento rýchly článok ukazuje, ako na to spracovávať riadky vo veľkom súbore bez opakovania a bez vyčerpania dostupnej pamäte - čo sa ukazuje ako veľmi užitočné pri práci s týmito veľkými súbormi.

Implementácia všetkých týchto príkladov a útržkov kódu nájdete v našom projekte GitHub - toto je projekt založený na Maven, takže by malo byť ľahké ho importovať a spustiť tak, ako je.


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