Kako učinkovito pročitati veliku datoteku s Javom

1. Pregled

Ovaj tutorial će pokazati kako pročitati sve retke iz velike datoteke na Javi na učinkovit način.

Ovaj je članak dio „Java - Povratak na Basic”Tutorial ovdje na Baeldungu.

2. Čitanje u memoriji

Standardni način čitanja redaka datoteke nalazi se u memoriji - i Guava i Apache Commons IO pružaju brz način za postizanje upravo toga:

Files.readLines (nova datoteka (put), znakovi.UTF_8);
FileUtils.readLines (nova datoteka (put));

Problem ovog pristupa je taj što se svi redovi datoteka čuvaju u memoriji - što će brzo dovesti do OutOfMemoryError ako je Datoteka dovoljno velika.

Na primjer - čitanje datoteke od ~ 1Gb:

@Test javna praznina givenUsingGuava_whenIteratingAFile_thenWorks () baca IOException {String path = ... Files.readLines (new File (path), Charsets.UTF_8); }

Ovo započinje s potrošnjom male količine memorije: (Potrošeno ~ 0 Mb)

[glavna] INFO org.baeldung.java.CoreJavaIoUnitTest - ukupna memorija: 128 Mb [glavna] INFO org.baeldung.java.CoreJavaIoUnitTest - besplatna memorija: 116 Mb

Međutim, nakon obrade pune datoteke, na kraju imamo: (Potrošeno ~ 2 Gb)

[glavna] INFO org.baeldung.java.CoreJavaIoUnitTest - ukupna memorija: 2666 Mb [glavna] INFO org.baeldung.java.CoreJavaIoUnitTest - besplatna memorija: 490 Mb

Što znači da proces troši oko 2,1 GB memorije - razlog je jednostavan - svi redovi datoteke sada se pohranjuju u memoriju.

U ovom bi trenutku trebalo biti očito da čuvanje u memoriji sadržaja datoteke brzo će iscrpiti dostupnu memoriju - bez obzira koliko je to zapravo.

Što je više, obično nam nisu potrebne sve linije u datoteci u memoriji odjednom - umjesto toga, samo trebamo biti u mogućnosti prelistati svaki od njih, obaviti neku obradu i baciti ga. Dakle, upravo ćemo to učiniti - prelistavati redove bez zadržavanja svih u sjećanju.

3. Strujanje kroz datoteku

Pogledajmo sada rješenje - koristit ćemo a java.util.Skener za prolazak kroz sadržaj datoteke i serijsko dohvaćanje redaka, jedan po jedan:

FileInputStream inputStream = null; Skener sc = null; isprobajte {inputStream = new FileInputStream (put); sc = novi skener (inputStream, "UTF-8"); while (sc.hasNextLine ()) {String line = sc.nextLine (); // System.out.println (linija); } // napominjemo da Scanner suzbija iznimke if (sc.ioException ()! = null) {throw sc.ioException (); }} napokon {if (inputStream! = null) {inputStream.close (); } if (sc! = null) {sc.close (); }}

Ovo rješenje će ponoviti sve retke u datoteci - omogućujući obradu svakog retka - bez zadržavanja referenci na njih - i u zaključku, ne zadržavajući ih u sjećanju: (Potrošeno ~ 150 Mb)

[glavna] INFO org.baeldung.java.CoreJavaIoUnitTest - ukupna memorija: 763 Mb [glavna] INFO org.baeldung.java.CoreJavaIoUnitTest - besplatna memorija: 605 Mb

4. Streaming s Apache Commons IO

Isto se može postići i korištenjem biblioteke Commons IO korištenjem običaj LineIterator knjižnica:

LineIterator it = FileUtils.lineIterator (datoteka, "UTF-8"); probajte {while (it.hasNext ()) {String line = it.nextLine (); // napravimo nešto s linijom}} konačno {LineIterator.closeQuietly (it); }

Budući da cijela datoteka nije u potpunosti u memoriji - to će rezultirati i prilično konzervativni brojevi potrošnje memorije: (Potrošeno ~ 150 Mb)

[glavna] INFO o.b.java.CoreJavaIoIntegrationTest - ukupna memorija: 752 Mb [glavna] INFO o.b.java.CoreJavaIoIntegrationTest - besplatna memorija: 564 Mb

5. Zaključak

Ovaj kratki članak pokazuje kako obraditi linije u velikoj datoteci bez ponavljanja, bez iscrpljivanja dostupne memorije - što se pokazuje vrlo korisno pri radu s tim velikim datotekama.

Implementacija svih ovih primjera i isječaka koda možete pronaći u našem GitHub projektu - ovo je projekt zasnovan na Mavenu, pa bi ga trebalo biti lako uvesti i pokrenuti kakav jest.


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