944 votes

Comment puis-je lire un grand fichier texte ligne par ligne en utilisant Java ?

Je dois lire un gros fichier texte d'environ 5-6 Go ligne par ligne en utilisant Java.

Comment puis-je faire cela rapidement?

83 votes

@kamaci et al. Cette question ne devrait pas être marquée comme un doublon. "Lire rapidement la dernière ligne" n'est pas une alternative, et il est discutable de savoir si "Manière la plus rapide de lire un fichier texte ligne par ligne" en est une. La manière la plus rapide de faire quelque chose n'est pas forcément la manière la plus commune. De plus, les réponses ci-dessous incluent du code, alors que l'alternative la plus pertinente que vous mentionnez ne le fait pas. Cette question est utile. Elle est actuellement en tête des résultats de recherche Google pour "java lire un fichier ligne par ligne". Enfin, il est décourageant d'arriver sur stack overflow et de constater que 1 question sur 2 est signalée pour être éliminée.

5 votes

Ici se trouve une comparaison de vitesse pour six implémentations possibles.

5 votes

Même si j'ai lu des commentaires argumentant que la politique de fermeture de SO est nulle, SO persiste. C'est une vision de développeur étroite d'esprit de vouloir éviter la redondance à tout prix! Laissez faire! La crème remontera naturellement et la m*rde coulera d'elle-même vers le bas. Même si une question a déjà été posée avant (quelle question ne l'a pas été ??), cela ne signifie pas qu'une nouvelle question ne pourrait pas la formuler mieux, obtenir de meilleures réponses, être mieux classée dans les moteurs de recherche, etc. D'ailleurs, cette question est maintenant 'protégée'...

1176voto

Peter Lawrey Points 229686

Un motif commun est d'utiliser

try (BufferedReader br = new BufferedReader(new FileReader(file))) {
    String line;
    while ((line = br.readLine()) != null) {
       // process the line.
    }
}

Vous pouvez lire les données plus rapidement si vous supposez qu'il n'y a pas de codage de caractères. par exemple ASCII-7 mais cela ne fera pas beaucoup de différence. Il est très probable que ce que vous faites avec les données prendra beaucoup plus de temps.

MODIFICATION : Un motif moins courant à utiliser qui évite la fuite de portée de line.

try(BufferedReader br = new BufferedReader(new FileReader(file))) {
    for(String line; (line = br.readLine()) != null; ) {
        // process the line.
    }
    // line n'est pas visible ici.
}

MISE À JOUR : En Java 8, vous pouvez faire

try (Stream stream = Files.lines(Paths.get(fileName))) {
        stream.forEach(System.out::println);
}

REMARQUE : Vous devez placer le Stream dans un bloc try-with-resource pour garantir que la méthode #close est appelée dessus, sinon la poignée de fichier sous-jacente ne sera jamais fermée jusqu'à ce que GC le fasse beaucoup plus tard.

6 votes

A quoi ressemble ce motif avec une gestion appropriée des exceptions? Je remarque que br.close() lance une IOException, ce qui semble surprenant - que pourrait-il se passer lors de la fermeture d'un fichier ouvert en lecture, de toute façon? Le constructeur de FileReader pourrait générer une exception FileNotFound.

0 votes

@MikeB En Java 7, vous ajouteriez un bloc try-with-resource. Close ne devrait pas déclencher d'exception, mais certaines implémentations pourraient le faire. Je ne m'attendrais pas à ce que BufferedReader en fasse partie. Il est très rare de voir les développeurs ajouter un traitement spécial pour close();

0 votes

Est-ce la vitesse maximale que Java peut atteindre ? J'ai un fichier d'environ 200 Mo que je lis avec cette méthode et c'est vraiment lent ... est-il possible d'utiliser quelque chose de plus rapide ? Lire sur plusieurs lignes ou quelque chose du genre ?

173voto

NAVEED Points 16576

Regardez ce blog :

La taille du tampon peut être spécifiée, ou la taille par défaut peut être utilisée. Par défaut, elle est suffisamment grande pour la plupart des besoins.

// Ouvrir le fichier
FileInputStream fstream = new FileInputStream("textfile.txt");

// Obtenez l'objet DataInputStream
DataInputStream in = new DataInputStream(fstream);
BufferedReader br = new BufferedReader(new InputStreamReader(in));

String strLine;

// Lire le fichier ligne par ligne
while ((strLine = br.readLine()) != null)   {
  // Afficher le contenu sur la console
  System.out.println (strLine);
}

// Fermer le flux d'entrée
in.close();

7 votes

Mon fichier fait 1,5 Gig et il n'est pas possible de lire le fichier en utilisant votre réponse!

4 votes

@AboozarRajabi Bien sûr que c'est possible. Ce code peut lire n'importe quel fichier texte.

11 votes

Downvoted pour la piètre qualité du lien. Il y a une DataInputStream totalement inutile, et le mauvais flux est fermé. Rien de mal avec le tutoriel Java, et pas besoin de citer des absurdités arbitraires de tiers sur Internet comme ça.

119voto

msayag Points 561

Une fois que Java 8 est sorti (mars 2014), vous pourrez utiliser des flux :

try (Stream lines = Files.lines(Paths.get(filename), Charset.defaultCharset())) {
  lines.forEachOrdered(line -> process(line));
}

Imprimer toutes les lignes dans le fichier :

try (Stream lines = Files.lines(file, Charset.defaultCharset())) {
  lines.forEachOrdered(System.out::println);
}

2 votes

Utilisez StandardCharsets.UTF_8, utilisez Stream pour la concision, et évitez d'utiliser forEach() et surtout forEachOrdered() sauf s'il y a une raison.

2 votes

Pourquoi éviter forEach()? Est-ce mauvais?

1 votes

Si j'utilise forEach au lieu de forEachOrdered, les lignes pourraient être imprimées dans le désordre, n'est-ce pas?

40voto

DarkStar Points 121

Voici un exemple avec une gestion d'erreur complète et la spécification de jeu de caractères pour les versions antérieures à Java 7. Avec Java 7, vous pouvez utiliser la syntaxe try-with-resources, ce qui rend le code plus propre.

Si vous voulez juste utiliser le jeu de caractères par défaut, vous pouvez sauter l'entrée InputStream et utiliser FileReader.

InputStream ins = null; // raw byte-stream
Reader r = null; // cooked reader
BufferedReader br = null; // tamponné pour readLine()
try {
    String s;
    if (true) {
        String data = "#foobar\t1234\n#xyz\t5678\none\ttwo\n";
        ins = new ByteArrayInputStream(data.getBytes());
    } else {
        ins = new FileInputStream("textfile.txt");
    }
    r = new InputStreamReader(ins, "UTF-8"); // laisser le jeu de caractères par défaut
    br = new BufferedReader(r);
    while ((s = br.readLine()) != null) {
        System.out.println(s);
    }
}
catch (Exception e)
{
    System.err.println(e.getMessage()); // gérer l'exception
}
finally {
    if (br != null) { try { br.close(); } catch(Throwable t) { /* assurer la fermeture */ } }
    if (r != null) { try { r.close(); } catch(Throwable t) { /* assurer la fermeture */ } }
    if (ins != null) { try { ins.close(); } catch(Throwable t) { /* assurer la fermeture */ } }
}

Voici la version Groovy, avec une gestion d'erreur complète :

File f = new File("textfile.txt");
f.withReader("UTF-8") { br ->
    br.eachLine { line ->
        println line;
    }
}

1 votes

Que fait un ByteArrayInputStream alimenté par une chaîne littérale en termes de lecture d'un grand fichier texte?

0 votes

Fermez absolument inutile. Il n'y a aucune raison de fermer chaque flux. Si vous fermez l'un de ces flux, vous fermez automatiquement tous les autres flux...

36voto

Pih Points 1641

Utilisez le BufferedReader, il lit, met dans un tampon (évidemment :-) ), puis jette le tampon:

BufferedReader in = new BufferedReader(new FileReader(file));

while (in.ready()) {
  String s = in.readLine();
}
in.close();

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X