Ich muss eine große Textdatei von ca. 5-6 GB Zeile für Zeile mit Java lesen.
Wie kann ich das schnell machen?
java
performance
file-io
io
garbage-collection
Manoj Singh
quelle
quelle
Antworten:
Ein übliches Muster ist zu verwenden
Sie können die Daten schneller lesen, wenn Sie davon ausgehen, dass keine Zeichencodierung vorhanden ist. zB ASCII-7, aber es macht keinen großen Unterschied. Es ist sehr wahrscheinlich, dass das, was Sie mit den Daten tun, viel länger dauert.
BEARBEITEN: Ein weniger verbreitetes Muster, das das Ausmaß von
line
Undichtigkeiten vermeidet .UPDATE: In Java 8 können Sie dies tun
ANMERKUNG: Sie müssen den Stream in einem Try-with-Resource- Block platzieren, um sicherzustellen, dass die # close-Methode darauf aufgerufen wird. Andernfalls wird das zugrunde liegende Dateihandle erst geschlossen, wenn GC dies viel später tut.
quelle
for(String line = br.readLine(); line != null; line = br.readLine())
übrigens, in Java 8 können Sie tun,try( Stream<String> lines = Files.lines(...) ){ for( String line : (Iterable<String>) lines::iterator ) { ... } }
was schwer zu hassen ist.Schauen Sie sich diesen Blog an:
quelle
DataInputStream
und der falsche Stream ist geschlossen. An dem Java-Lernprogramm ist nichts auszusetzen, und es ist nicht erforderlich, willkürlichen Internet-Müll von Drittanbietern wie diesen zu zitieren.Sobald Java 8 veröffentlicht ist (März 2014), können Sie Streams verwenden:
Drucken aller Zeilen in der Datei:
quelle
StandardCharsets.UTF_8
, verwenden SieStream<String>
für die Prägnanz und vermeiden Sie die VerwendungforEach()
und insbesondere,forEachOrdered()
wenn es keinen Grund gibt.forEach(this::process)
, aber es wird hässlich, wenn Sie Codeblöcke als Lambdas darin schreibenforEach()
.forEachOrdered
, um in der richtigen Reihenfolge auszuführen. Beachten Sie, dass Sie den Stream in diesem Fall nicht parallelisieren können, obwohl ich festgestellt habe, dass die Parallelisierung nur aktiviert wird, wenn die Datei Tausende von Zeilen enthält.Hier ist ein Beispiel mit vollständiger Fehlerbehandlung und unterstützender Zeichensatzspezifikation für Pre-Java 7. Mit Java 7 können Sie die Try-with-Resources-Syntax verwenden, wodurch der Code sauberer wird.
Wenn Sie nur den Standardzeichensatz möchten, können Sie den InputStream überspringen und FileReader verwenden.
Hier ist die Groovy-Version mit vollständiger Fehlerbehandlung:
quelle
ByteArrayInputStream
von einem String gespeistes Literal mit dem Lesen einer großen Textdatei zu tun?In Java 8 können Sie Folgendes tun:
Einige Hinweise: Der von
Files.lines
(im Gegensatz zu den meisten Streams) zurückgegebene Stream muss geschlossen werden. Aus den hier genannten Gründen vermeide ich die VerwendungforEach()
. Der seltsame Code(Iterable<String>) lines::iterator
wandelt einen Stream in ein Iterable um.quelle
Iterable
dieser Code nicht implementiert wird, ist er definitiv hässlich, obwohl er nützlich ist. Es braucht eine Besetzung (dh(Iterable<String>)
), um zu arbeiten.for(String line : (Iterable<String>) lines.skip(1)::iterator)
Stream
, scheint es viel einfacher zu sein , KonstrukteureFiles.newBufferedReader
anstelle vonFiles.lines
und wiederholt aufzurufen,readLine()
bis sienull
anstelle von Konstrukten wie verwendet(Iterable<String>) lines::iterator
werden…Sie können den gesamten Text mit dem Scanner scannen und den Text zeilenweise durchgehen. Natürlich sollten Sie Folgendes importieren:
Der Scanner scannt grundsätzlich den gesamten Text. Die while-Schleife wird verwendet, um den gesamten Text zu durchlaufen.
Die
.hasNextLine()
Funktion ist ein Boolescher Wert, der true zurückgibt, wenn der Text noch mehr Zeilen enthält. Die.nextLine()
Funktion gibt Ihnen eine ganze Zeile als Zeichenfolge, die Sie dann nach Ihren Wünschen verwenden können. Versuchen SieSystem.out.println(line)
, den Text zu drucken.Randnotiz: .txt ist der Dateityptext.
quelle
BufferedReader.readLine()
, und er fragte nach der leistungsstärksten Methode.Mit FileReader können Sie die Codierung nicht angeben. Verwenden Sie sie
InputStreamReader
stattdessen, wenn Sie sie angeben müssen:Wenn Sie diese Datei aus Windows importiert haben, verfügt sie möglicherweise über eine ANSI-Codierung (Cp1252), daher müssen Sie die Codierung angeben.
quelle
Ich habe 10 verschiedene Möglichkeiten zum Lesen einer Datei in Java dokumentiert und getestet und sie dann gegeneinander ausgeführt, indem ich sie in Testdateien von 1 KB bis 1 GB einlesen ließ. Hier sind die schnellsten 3 Methoden zum Lesen von Dateien zum Lesen einer 1-GB-Testdatei.
Beachten Sie, dass ich beim Ausführen der Leistungstests nichts an die Konsole ausgegeben habe, da dies den Test wirklich verlangsamen würde. Ich wollte nur die rohe Lesegeschwindigkeit testen.
1) java.nio.file.Files.readAllBytes ()
Getestet in Java 7, 8, 9. Dies war insgesamt die schnellste Methode. Das Lesen einer 1-GB-Datei dauerte durchweg knapp 1 Sekunde.
2) java.nio.file.Files.lines ()
Dies wurde erfolgreich in Java 8 und 9 getestet, funktioniert jedoch in Java 7 nicht, da Lambda-Ausdrücke nicht unterstützt werden. Das Einlesen einer 1-GB-Datei dauerte ungefähr 3,5 Sekunden, womit sie beim Lesen größerer Dateien an zweiter Stelle stand.
3) BufferedReader
Getestet für Java 7, 8, 9. Das Einlesen einer 1-GB-Testdatei dauerte ca. 4,5 Sekunden.
Die vollständige Rangliste für alle 10 Methoden zum Lesen von Dateien finden Sie hier .
quelle
System.out.print/println()
hier meistens ; Sie gehen auch davon aus, dass die Datei in Ihren ersten beiden Fällen in den Speicher passt.In Java 7:
quelle
StandardCharsets.UTF_8
, um die aktivierte Ausnahme inCharset.forName("UTF-8")
In Java 8 gibt es auch eine Alternative zur Verwendung
Files.lines()
. Wenn Ihre Eingabequelle keine Datei ist, sondern etwas Abstrakteres wie aReader
oder anInputStream
, können Sie die Zeilen über die Methode s streamen .BufferedReader
lines()
Zum Beispiel:
ruft
processLine()
für jede Eingabezeile auf, die von der gelesen wirdBufferedReader
.quelle
Zum Lesen einer Datei mit Java 8
quelle
Sie können die Scannerklasse verwenden
quelle
Scanner
ist in Ordnung, aber diese Antwort enthält nicht den vollständigen Code, um sie ordnungsgemäß zu verwenden.BufferedReader.readLine()
sicherlich um ein Vielfaches schneller ist. Wenn Sie anders denken, geben Sie bitte Ihre Gründe an.Sie müssen die
readLine()
Methode in verwendenclass BufferedReader
. Erstellen Sie ein neues Objekt aus dieser Klasse, führen Sie diese Methode für ihn aus und speichern Sie es in einer Zeichenfolge.BufferReader Javadoc
quelle
Der klare Weg, um dies zu erreichen,
Zum Beispiel:
Wenn Sie
dataFile.txt
in Ihrem aktuellen Verzeichnis habenDie Ausgabe wie folgt,
quelle
Java 9:
quelle
System.getProperty("os.name").equals("Linux")
==
!Für mich geht das. Hoffe, es wird dir auch helfen.
quelle
Sie können Streams verwenden, um dies genauer zu tun:
quelle
Normalerweise mache ich die Leseroutine unkompliziert:
quelle
Sie können diesen Code verwenden:
quelle
Durch die Verwendung des Pakets org.apache.commons.io wurde eine höhere Leistung erzielt , insbesondere bei Legacy-Code, der Java 6 und niedriger verwendet.
Java 7 verfügt über eine bessere API mit weniger Ausnahmebehandlung und nützlicheren Methoden:
Maven
quelle
Sie können auch Apache Commons IO verwenden :
quelle
FileUtils.readLines(file)
ist eine veraltete Methode. Darüber hinaus ruft die Methode aufIOUtils.readLines
, die einen BufferedReader und eine ArrayList verwendet. Dies ist keine zeilenweise Methode und sicherlich keine, die zum Lesen mehrerer GB praktisch wäre.