web-dev-qa-db-de.com

Wie kann ich die Anzahl der Zeilen in einer Datei effizient ermitteln?

Ich habe eine große Datei. Es umfasst ungefähr 3.000-20.000 Zeilen. Wie kann ich die Gesamtanzahl der Zeilen in der Datei mithilfe von Java ermitteln?

61
firstthumb
BufferedReader reader = new BufferedReader(new FileReader("file.txt"));
int lines = 0;
while (reader.readLine() != null) lines++;
reader.close();

Update: Um die hier aufgeworfene Performance-Frage zu beantworten, habe ich eine Messung durchgeführt. Erstens: 20.000 Zeilen sind zu wenig, um das Programm spürbar laufen zu lassen. Ich habe eine Textdatei mit 5 Millionen Zeilen erstellt. Diese Lösung (gestartet mit Java ohne Parameter wie -server oder -XX-options) benötigte für meine Box etwa 11 Sekunden. Dasselbe gilt für wc -l (UNIX-Befehlszeilenprogramm zum Zählen von Zeilen), 11 Sekunden. Die Lösung, die jedes einzelne Zeichen las und nach '\ n' suchte, benötigte 104 Sekunden, 9-10 mal so viel.

96
Mnementh

Files.lines

Java 8+ hat einen sehr schönen und kurzen Weg mit NIO mit Files.lines .

Path path = Paths.get("./big_file.txt");
long lineCount = Files.lines(path).count();

Die Standard-Zeichenkodierung in UTF-8 . Sie können eine alternative Kodierung angeben , die Ihrer bestimmten Datendatei entspricht.

39
Augustin

verwenden Sie LineNumberReader

so etwas wie

public static int countLines(File aFile) throws IOException {
    LineNumberReader reader = null;
    try {
        reader = new LineNumberReader(new FileReader(aFile));
        while ((reader.readLine()) != null);
        return reader.getLineNumber();
    } catch (Exception ex) {
        return -1;
    } finally { 
        if(reader != null) 
            reader.close();
    }
}
32
Narayan

Ich habe dafür eine Lösung gefunden, die für Sie nützlich sein könnte

Unten ist der Code-Ausschnitt für die Anzahl der Zeilen aus der Datei.

  File file = new File("/mnt/sdcard/abc.txt");
  LineNumberReader lineNumberReader = new LineNumberReader(new FileReader(file));
  lineNumberReader.skip(Long.MAX_VALUE);
  int lines = lineNumberReader.getLineNumber();
  lineNumberReader.close();
10
brig

Lesen Sie die Datei durch und zählen Sie die Anzahl der Zeilenumbrüche. Eine einfache Möglichkeit, eine Datei in Java Zeile für Zeile zu lesen, ist die Klasse Java.util.Scanner .

4
Esko Luontola

Dies ist ungefähr so ​​effizient wie es möglich ist, gepuffertes binäres Lesen, keine String-Umwandlung,

FileInputStream stream = new FileInputStream("/tmp/test.txt");
byte[] buffer = new byte[8192];
int count = 0;
int n;
while ((n = stream.read(buffer)) > 0) {
    for (int i = 0; i < n; i++) {
        if (buffer[i] == '\n') count++;
    }
}
stream.close();
System.out.println("Number of lines: " + count);
4
ZZ Coder

Benötigen Sie eine genaue Anzahl von Zeilen oder nur deren Näherung? Ich verarbeite große Dateien parallel, und oft muss ich die genaue Anzahl der Zeilen nicht kennen - ich verwende dann das Sampling. Teilen Sie die Datei in zehn 1-MB-Blöcke auf und zählen Sie die Zeilen in jedem Block, multiplizieren Sie sie mit 10 und Sie erhalten eine ziemlich gute Annäherung an die Zeilenanzahl.

3
matt

Alle vorherigen Antworten schlagen vor, die gesamte Datei zu lesen und die Anzahl der Zeilenumbrüche zu zählen, die Sie dabei finden. Sie haben einige als "nicht effektiv" kommentiert, aber nur so können Sie das schaffen. Eine "Zeile" ist nichts anderes als ein einfaches Zeichen in der Datei. Und um dieses Zeichen zu zählen, müssen Sie sich jedes einzelne Zeichen in der Datei ansehen.

Es tut mir leid, aber Sie haben keine Wahl. :-)

2
Malax

Wenn die bereits veröffentlichten Antworten nicht schnell genug sind, müssen Sie wahrscheinlich nach einer für Ihr Problem spezifischen Lösung suchen.

Wenn diese Textdateien beispielsweise Protokolle sind, an die nur angefügt werden und Sie regelmäßig die Anzahl der Zeilen kennen müssen, können Sie einen Index erstellen. Dieser Index würde die Anzahl der Zeilen in der Datei enthalten, wann die Datei zuletzt geändert wurde und wie groß die Datei damals war. Auf diese Weise können Sie die Anzahl der Zeilen in der Datei neu berechnen, indem Sie alle Zeilen, die Sie bereits gesehen haben, überspringen und nur die neuen Zeilen lesen.

2
blackNBUK

Diese Lösung ist etwa 3,6 × schneller als die am besten bewertete Antwort, wenn eine Datei mit 13,8 Millionen Zeilen getestet wurde. Es liest einfach die Bytes in einen Puffer und zählt die \n-Zeichen. Sie könnten mit der Puffergröße spielen, aber auf meinem Computer wurde der Code mit etwas mehr als 8 KB nicht schneller.

private int countLines(File file) throws IOException {
    int lines = 0;

    FileInputStream fis = new FileInputStream(file);
    byte[] buffer = new byte[BUFFER_SIZE]; // BUFFER_SIZE = 8 * 1024
    int read;

    while ((read = fis.read(buffer)) != -1) {
        for (int i = 0; i < read; i++) {
            if (buffer[i] == '\n') lines++;
        }
    }

    fis.close();

    return lines;
}
2
fhucho

Schnell und schmutzig, aber es macht den Job:

import Java.io.*;

public class Counter {

    public final static void main(String[] args) throws IOException {
        if (args.length > 0) {
            File file = new File(args[0]);
            System.out.println(countLines(file));
        }
    }

    public final static int countLines(File file) throws IOException {
        ProcessBuilder builder = new ProcessBuilder("wc", "-l", file.getAbsolutePath());
        Process process = builder.start();
        InputStream in = process.getInputStream();
        LineNumberReader reader = new LineNumberReader(new InputStreamReader(in));
        String line = reader.readLine();
        if (line != null) {
            return Integer.parseInt(line.trim().split(" ")[0]);
        } else {
            return -1;
        }
    }

}
2

Alte Post, aber ich habe eine Lösung, die für die nächsten Leute nützlich sein könnte. Warum verwenden Sie nicht einfach die Dateilänge, um zu wissen, wie der Fortschritt aussieht? Natürlich müssen Zeilen fast die gleiche Größe haben, aber sie funktionieren sehr gut für große Dateien:

public static void main(String[] args) throws IOException {
    File file = new File("yourfilehere");
    double fileSize = file.length();
    System.out.println("=======> File size = " + fileSize);
    InputStream inputStream = new FileInputStream(file);
    InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "iso-8859-1");
    BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
    int totalRead = 0;
    try {
        while (bufferedReader.ready()) {
            String line = bufferedReader.readLine();
            // LINE PROCESSING HERE
            totalRead += line.length() + 1; // we add +1 byte for the newline char.
            System.out.println("Progress ===> " + ((totalRead / fileSize) * 100) + " %");
        }
    } finally {
        bufferedReader.close();
    }
}

Es erlaubt den Fortschritt zu sehen, ohne die Datei vollständig zu lesen. Ich weiß, dass es von vielen Elementen abhängt, aber ich hoffe, es wird nützlich sein :).

[Edition] Hier ist eine Version mit geschätzter Zeit. Ich habe ein paar SYSO gesetzt, um Fortschritt und Schätzung zu zeigen. Ich sehe, dass Sie einen guten Zeitschätzungsfehler haben, nachdem Sie genügend Linie behandelt haben (ich versuche es mit 10M-Linien, und nach 1% der Behandlung war die Zeitschätzung bei 95% genau). Ich weiß, dass einige Werte vorliegen in Variable gesetzt werden. Dieser Code ist schnell geschrieben, aber für mich nützlich. Ich hoffe es wird auch für dich sein :).

long startProcessLine = System.currentTimeMillis();
    int totalRead = 0;
    long progressTime = 0;
    double percent = 0;
    int i = 0;
    int j = 0;
    int fullEstimation = 0;
    try {
        while (bufferedReader.ready()) {
            String line = bufferedReader.readLine();
            totalRead += line.length() + 1;
            progressTime = System.currentTimeMillis() - startProcessLine;
            percent = (double) totalRead / fileSize * 100;
            if ((percent > 1) && i % 10000 == 0) {
                int estimation = (int) ((progressTime / percent) * (100 - percent));
                fullEstimation += progressTime + estimation;
                j++;
                System.out.print("Progress ===> " + percent + " %");
                System.out.print(" - current progress : " + (progressTime) + " milliseconds");
                System.out.print(" - Will be finished in ===> " + estimation + " milliseconds");
                System.out.println(" - estimated full time => " + (progressTime + estimation));
            }
            i++;
        }
    } finally {
        bufferedReader.close();
    }
    System.out.println("Ended in " + (progressTime) + " seconds");
    System.out.println("Estimative average ===> " + (fullEstimation / j));
    System.out.println("Difference: " + ((((double) 100 / (double) progressTime)) * (progressTime - (fullEstimation / j))) + "%");

Fühlen Sie sich frei, diesen Code zu verbessern, wenn Sie der Meinung sind, dass dies eine gute Lösung ist.

1
lpratlong

Versuchen Sie den Unix-Befehl "wc". Ich meine nicht, benutze es, ich meine, lade die Quelle herunter und schaue, wie sie es tun. Es ist wahrscheinlich in c, aber Sie können das Verhalten leicht auf Java portieren. Das Problem bei der Erstellung eines eigenen ist, das endende cr/lf-Problem zu berücksichtigen. 

1
Daniel

In meinen Tests dauern die anderen Antworten ~ 150-300 ms für eine 118.5k-Zeilendatei ..__ Die folgenden Schritte dauern 1ms, sind jedoch nur ungefähr (meldet 117k-Zeilen) und hängt davon ab, ob jede Zeile eine ähnliche Größe hat.

private static void countSize(File file) {
  long fileLength = file.length();
  BufferedReader reader = null;
  try {
    reader = new BufferedReader(new FileReader(file));
    //Skip header as it is of different size
    reader.readLine();
    String text = reader.readLine();
    int lineLength = text.length();
    long lines = fileLength / lineLength;
    System.out.println(lines);
  } catch(IOException e) {
    e.printStackTrace();
  } finally {
    if(reader != null) {
      try {
        reader.close();
      } catch(IOException e) {
        //no-op
      }
    }
  }
}
0
opticyclic

Lesen Sie die Datei Zeile für Zeile und erhöhen Sie einen Zähler für jede Zeile, bis Sie die gesamte Datei gelesen haben.

0
Ken Liu