Dies ist die schnellste Version, die ich bisher gefunden habe, ungefähr sechsmal schneller als readLines. Bei einer 150-MB-Protokolldatei dauert dies 0,35 Sekunden, bei Verwendung von readLines () 2,40 Sekunden. Nur zum Spaß dauert der Befehl wc -l von Linux 0,15 Sekunden.
public static int countLinesOld(String filename) throws IOException {
InputStream is = new BufferedInputStream(new FileInputStream(filename));
try {
byte[] c = new byte[1024];
int count = 0;
int readChars = 0;
boolean empty = true;
while ((readChars = is.read(c)) != -1) {
empty = false;
for (int i = 0; i < readChars; ++i) {
if (c[i] == '\n') {
++count;
}
}
}
return (count == 0 && !empty) ? 1 : count;
} finally {
is.close();
}
}
EDIT, 9 1/2 Jahre später: Ich habe praktisch keine Java-Erfahrung, aber trotzdem habe ich versucht, diesen Code mit der folgenden LineNumberReader
Lösung zu vergleichen, da es mich störte, dass niemand es tat. Es scheint, dass meine Lösung besonders für große Dateien schneller ist. Obwohl es ein paar Läufe zu dauern scheint, bis der Optimierer einen anständigen Job macht. Ich habe ein bisschen mit dem Code gespielt und eine neue Version erstellt, die durchweg am schnellsten ist:
public static int countLinesNew(String filename) throws IOException {
InputStream is = new BufferedInputStream(new FileInputStream(filename));
try {
byte[] c = new byte[1024];
int readChars = is.read(c);
if (readChars == -1) {
// bail out if nothing to read
return 0;
}
// make it easy for the optimizer to tune this loop
int count = 0;
while (readChars == 1024) {
for (int i=0; i<1024;) {
if (c[i++] == '\n') {
++count;
}
}
readChars = is.read(c);
}
// count remaining characters
while (readChars != -1) {
System.out.println(readChars);
for (int i=0; i<readChars; ++i) {
if (c[i] == '\n') {
++count;
}
}
readChars = is.read(c);
}
return count == 0 ? 1 : count;
} finally {
is.close();
}
}
Benchmark-Ergebnisse für eine 1,3-GB-Textdatei, y-Achse in Sekunden. Ich habe 100 Läufe mit derselben Datei durchgeführt und jeden Lauf mit gemessen System.nanoTime()
. Sie können sehen, dass countLinesOld
es einige Ausreißer gibt und countLinesNew
keine, und obwohl es nur ein bisschen schneller ist, ist der Unterschied statistisch signifikant. LineNumberReader
ist deutlich langsamer.
Ich habe eine andere Lösung für das Problem implementiert und fand es effizienter beim Zählen von Zeilen:
quelle
LineNumberReader
DaslineNumber
Feld ist eine Ganzzahl ... Wird es nicht nur für Dateien umbrochen, die länger als Integer.MAX_VALUE sind? Warum hier lange vorbeischauen?wc -l
zählt die Anzahl der Zeilenumbrüche in der Datei. Dies funktioniert, da jede Zeile mit einer neuen Zeile abgeschlossen wird, einschließlich der letzten Zeile in einer Datei. Jede Zeile hat ein Zeilenumbruchzeichen, einschließlich der Leerzeilen, daher ist die Anzahl der Zeilenumbrüche Zeichen == Anzahl der Zeilen in einer Datei. Jetzt repräsentiert dielineNumber
Variable inFileNumberReader
auch die Anzahl der gesehenen Zeilenumbrüche. Es beginnt bei Null, bevor eine neue Zeile gefunden wurde, und wird mit jedem gesehenen Zeilenumbruch erhöht. Fügen Sie also bitte keine zur Zeilennummer hinzu.wc -l
auch diese Art von Datei gemeldet . Siehe auch stackoverflow.com/questions/729692/…wc -l
1 zurückgeben. Ich kam zu dem Schluss, dass alle Methoden Fehler aufweisen, und implementierte eine basierend auf meinem Verhalten. Siehe meine andere Antwort hier.Die akzeptierte Antwort hat einen Fehler von um eins für Dateien mit mehreren Zeilen, die nicht mit Zeilenumbruch enden. Eine einzeilige Datei, die ohne Zeilenumbruch endet, würde 1 zurückgeben, eine zweizeilige Datei, die ohne Zeilenumbruch endet, würde ebenfalls 1 zurückgeben. Hier ist eine Implementierung der akzeptierten Lösung, die dies behebt. Die EndsWithoutNewLine-Überprüfungen sind für alles außer dem endgültigen Lesen verschwenderisch, sollten jedoch im Vergleich zur Gesamtfunktion zeitlich trivial sein.
quelle
Mit Java-8können Sie Streams verwenden:
quelle
Die Antwort mit der obigen Methode count () gab mir Zeilenfehler, wenn eine Datei am Ende der Datei keine neue Zeile hatte - die letzte Zeile in der Datei konnte nicht gezählt werden.
Diese Methode funktioniert besser für mich:
quelle
cnt
.Ich weiß, dass dies eine alte Frage ist, aber die akzeptierte Lösung stimmte nicht ganz mit dem überein, wofür ich sie brauchte. Daher habe ich es verfeinert, um verschiedene Zeilenabschlüsse (und nicht nur Zeilenvorschub) zu akzeptieren und eine bestimmte Zeichencodierung (anstelle von ISO-8859- n ) zu verwenden. Alles in einer Methode (Refactor nach Bedarf):
Diese Lösung ist in der Geschwindigkeit mit der akzeptierten Lösung vergleichbar und in meinen Tests etwa 4% langsamer (obwohl Timing-Tests in Java notorisch unzuverlässig sind).
quelle
Ich habe die obigen Methoden zum Zählen von Linien getestet und hier sind meine Beobachtungen für verschiedene Methoden, die auf meinem System getestet wurden
Dateigröße: 1,6 GB Methoden:
Darüber hinaus scheint der Java8- Ansatz recht praktisch zu sein:
quelle
Getestet auf JDK8_u31. In der Tat ist die Leistung im Vergleich zu dieser Methode langsam:
Getestet und sehr schnell.
quelle
Stream<String> - Time consumed: 122796351 Stream<String> - Num lines: 109808 Method - Time consumed: 12838000 Method - Num lines: 1
Und die Anzahl der Zeilen ist sogar falschBufferedInputStream
Sie ohnehin kein verwenden, wenn Sie in Ihren eigenen Puffer lesen möchten. Selbst wenn Ihre Methode einen geringfügigen Leistungsvorteil aufweist, verliert sie an Flexibilität, da sie nicht mehr alleinige\r
Terminatoren (altes MacOS) unterstützt und nicht jede Codierung unterstützt.Ein einfacher Weg mit Scanner
quelle
Ich kam zu dem Schluss, dass
wc -l
: s Methode zum Zählen von Zeilenumbrüchen in Ordnung ist, aber nicht intuitive Ergebnisse für Dateien zurückgibt, bei denen die letzte Zeile nicht mit einem Zeilenumbruch endet.Die auf LineNumberReader basierende @ er.vikas-Lösung, bei der jedoch eine zur Zeilenanzahl hinzugefügt wurde, ergab nicht intuitive Ergebnisse für Dateien, bei denen die letzte Zeile mit einer neuen Zeile endet.
Ich habe daher ein Algo erstellt, das wie folgt funktioniert:
Und es sieht so aus:
Wenn Sie intuitive Ergebnisse wünschen, können Sie diese verwenden. Wenn Sie nur
wc -l
Kompatibilität wünschen , verwenden Sie einfach die @ er.vikas-Lösung, fügen Sie jedoch keine zum Ergebnis hinzu und wiederholen Sie den Sprung:quelle
Wie wäre es mit der Process-Klasse aus Java-Code heraus? Und dann die Ausgabe des Befehls lesen.
Müssen es aber versuchen. Wird die Ergebnisse veröffentlichen.
quelle
Wenn Sie keine Indexstrukturen haben, können Sie die gesamte Datei nicht lesen. Sie können es jedoch optimieren, indem Sie vermeiden, es Zeile für Zeile zu lesen, und einen regulären Ausdruck verwenden, der allen Zeilenabschlusszeichen entspricht.
quelle
Diese lustige Lösung funktioniert wirklich gut!
quelle
Verwenden Sie auf Unix-basierten Systemen den
wc
Befehl in der Befehlszeile.quelle
Sie können nur wissen, wie viele Zeilen sich in der Datei befinden, indem Sie sie zählen. Sie können natürlich eine Metrik aus Ihren Daten erstellen, die eine durchschnittliche Länge von einer Zeile ergibt. Anschließend können Sie die Dateigröße ermitteln und diese durch den Durchschnitt teilen. Länge, aber das wird nicht genau sein.
quelle
Bester optimierter Code für mehrzeilige Dateien ohne Zeilenumbruch ('\ n') bei EOF.
quelle
Scanner mit Regex:
Habe es nicht getaktet.
quelle
wenn Sie dies verwenden
Sie können nicht zu großen Zeilen laufen, mag 100.000 Zeilen, weil die Rückgabe von reader.getLineNumber int ist. Sie benötigen lange Datentypen, um maximale Zeilen zu verarbeiten.
quelle
int
kann Werte von bis zu ungefähr 2 Milliarden halten. Wenn Sie eine Datei mit mehr als 2 Milliarden Zeilen laden, liegt ein Überlaufproblem vor. Wenn Sie jedoch eine nicht indizierte Textdatei mit mehr als zwei Milliarden Zeilen laden, haben Sie wahrscheinlich andere Probleme.