web-dev-qa-db-fra.com

Comment puis-je obtenir le nombre de lignes dans un fichier de manière efficace?

J'ai un gros fichier. Il comprend environ 3 000 à 20 000 lignes. Comment puis-je obtenir le nombre total de lignes du fichier en utilisant Java?

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

Mise à jour: Pour répondre à la question de performance posée ici, j'ai effectué une mesure. Première chose: 20 000 lignes sont trop peu nombreuses pour que le programme fonctionne pendant un temps considérable. J'ai créé un fichier texte de 5 millions de lignes. Cette solution (démarrée avec Java sans paramètres tels que -server ou -XX-options) a nécessité environ 11 secondes sur ma machine. Idem avec wc -l (outil de ligne de commande UNIX pour compter les lignes), 11 secondes. La solution lisant chaque caractère et recherchant '\ n' avait besoin de 104 secondes, soit 9 à 10 fois plus.

96
Mnementh

Files.lines

Java 8+ a un chemin très agréable et court en utilisant NIO en utilisant Files.lines .

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

Le codage de caractères par défaut dans UTF-8 . Vous pouvez spécifier un autre codage pour correspondre à votre fichier de données particulier.

39
Augustin

utiliser LineNumberReader

quelque chose comme

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

J'ai trouvé une solution pour cela, cela pourrait vous être utile

Voici l'extrait de code pour, comptez le nombre de lignes du fichier.

  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

Lisez le fichier et comptez le nombre de caractères de nouvelle ligne. Un moyen simple de lire un fichier en Java, une ligne à la fois, est le fichier Java.util.Scanner class.

4
Esko Luontola

C’est à peu près aussi efficace que possible, lecture binaire en mémoire tampon, aucune conversion de chaîne,

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

Avez-vous besoin du nombre exact de lignes ou seulement de son approximation? Il m'est arrivé de traiter des fichiers volumineux en parallèle et souvent je n'ai pas besoin de connaître le nombre exact de lignes - je retourne ensuite à l'échantillonnage. Divisez le fichier en dix morceaux de 1 Mo et comptez les lignes dans chaque morceau, puis multipliez-le par 10 et vous recevrez une assez bonne approximation du nombre de lignes.

3
matt

Toutes les réponses précédentes suggèrent de lire l'intégralité du fichier et de compter le nombre de nouvelles lignes trouvées. Vous avez commenté certains comme "non efficaces" mais c’est la seule façon de le faire. Une "ligne" n'est rien d'autre qu'un simple caractère à l'intérieur du fichier. Et pour compter ce caractère, vous devez examiner chaque caractère du fichier.

Je suis désolé, mais tu n'as pas le choix. :-)

2
Malax

Si les réponses déjà publiées ne sont pas assez rapides, vous devrez probablement rechercher une solution spécifique à votre problème.

Par exemple, si ces fichiers texte sont des journaux uniquement ajoutés et que vous devez régulièrement connaître le nombre de lignes, vous pouvez créer un index. Cet index contiendrait le nombre de lignes dans le fichier, la date de la dernière modification du fichier et sa taille. Cela vous permettrait de recalculer le nombre de lignes du fichier en sautant toutes les lignes déjà vues et en ne lisant que les nouvelles lignes.

2
blackNBUK

Cette solution est environ 3,6 × plus rapide que la réponse la mieux notée lorsqu'elle est testée sur un fichier de 13,8 millions de lignes. Il lit simplement les octets dans un tampon et compte les caractères \n. Vous pouvez jouer avec la taille de la mémoire tampon, mais sur ma machine, tout ce qui dépasse 8 Ko ne rend pas le code plus rapide.

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

Rapide et sale, mais ça fait le travail:

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
Wilfred Springer

Ancien post, mais j'ai une solution qui pourrait être utile pour les prochaines personnes ..__ Pourquoi ne pas simplement utiliser la longueur du fichier pour savoir quelle est la progression? Bien sûr, les lignes doivent avoir presque la même taille, mais cela fonctionne très bien pour les gros fichiers:

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();
    }
}

Cela permet de voir la progression sans faire de lecture complète sur le fichier. Je sais que cela dépend de nombreux éléments, mais j'espère que ce sera utile :).

[Edition] Voici une version avec une heure estimée. Je mets du SYSO pour montrer les progrès et les estimations. Je vois que vous avez une bonne erreur d’estimation du temps après avoir traité assez de ligne (j’essaie avec 10 millions de lignes et après 1% du traitement, l’estimation du temps était exacte à 95%) être mis en variable. Ce code est écrit rapidement mais a été utile pour moi. J'espère que ce sera pour vous aussi :).

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))) + "%");

N'hésitez pas à améliorer ce code si vous pensez que c'est une bonne solution.

1
lpratlong

Essayez la commande unix "wc". Je ne veux pas dire l’utiliser, je veux dire télécharger la source et voir comment ils le font. C'est probablement en c, mais vous pouvez facilement transférer le comportement en Java. Le problème avec la création de votre propre est de rendre compte du problème final cr/lf. 

1
Daniel

Dans mes tests, les autres réponses prennent environ 150 à 300 ms sur un fichier de ligne de 118,5 Ko .

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

Lisez le fichier ligne par ligne et incrémentez un compteur pour chaque ligne jusqu'à ce que vous ayez lu tout le fichier.

0
Ken Liu