J'ai besoin de lire un gros fichier texte d'environ 5-6 Go ligne par ligne en utilisant Java.
Comment puis-je le faire rapidement?
java
performance
file-io
io
garbage-collection
manoj singh
la source
la source
Réponses:
Un modèle courant consiste à utiliser
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 fort probable que ce que vous faites avec les données prenne beaucoup plus de temps.
EDIT: un modèle moins courant à utiliser qui évite l'ampleur des
line
fuites.MISE À JOUR: Dans Java 8, vous pouvez faire
REMARQUE: Vous devez placer le Stream dans un bloc try-with-resource pour vous assurer que la méthode #close est appelée dessus, sinon le descripteur de fichier sous-jacent n'est jamais fermé jusqu'à ce que GC le fasse beaucoup plus tard.
la source
for(String line = br.readLine(); line != null; line = br.readLine())
Btw, en Java 8 vous pouvez fairetry( Stream<String> lines = Files.lines(...) ){ for( String line : (Iterable<String>) lines::iterator ) { ... } }
ce qui est difficile à ne pas haïr.Regardez ce blog:
la source
DataInputStream
, et le mauvais flux est fermé. Rien de mal avec le tutoriel Java, et pas besoin de citer des déchets Internet tiers arbitraires comme celui-ci.Une fois Java 8 sorti (mars 2014), vous pourrez utiliser des flux:
Impression de toutes les lignes du fichier:
la source
StandardCharsets.UTF_8
, utilisezStream<String>
pour la concision, et évitez d'utiliserforEach()
et surtout àforEachOrdered()
moins qu'il y ait une raison.forEach(this::process)
, mais cela devient moche si vous écrivez des blocs de code en tant que lambdas à l'intérieurforEach()
.forEachOrdered
pour exécuter dans l'ordre. Sachez que vous ne pourrez pas paralléliser le flux dans ce cas, même si j'ai constaté que la parallélisation ne s'active que si le fichier contient des milliers de lignes.Voici un exemple avec gestion complète des erreurs et prise en charge de la spécification de jeu de caractères pour pré-Java 7. Avec Java 7, vous pouvez utiliser la syntaxe try-with-resources, qui rend le code plus propre.
Si vous voulez juste le jeu de caractères par défaut, vous pouvez ignorer InputStream et utiliser FileReader.
Voici la version Groovy, avec une gestion complète des erreurs:
la source
ByteArrayInputStream
littéral alimenté par une chaîne a à voir avec la lecture d'un gros fichier texte?En Java 8, vous pourriez faire:
Quelques notes: Le flux renvoyé par
Files.lines
(contrairement à la plupart des flux) doit être fermé. Pour les raisons mentionnées ici, j'évite d'utiliserforEach()
. L'étrange code(Iterable<String>) lines::iterator
transforme un Stream en Iterable.la source
Iterable
ce code est définitivement moche bien qu'utile. Il a besoin d'un casting (ie(Iterable<String>)
) pour fonctionner.for(String line : (Iterable<String>) lines.skip(1)::iterator)
Stream
fonctionnalités, utiliserFiles.newBufferedReader
au lieu d'Files.lines
appeler et répéterreadLine()
jusqu'à ce que,null
au lieu d'utiliser des constructions comme(Iterable<String>) lines::iterator
semble être beaucoup plus simple…Ce que vous pouvez faire est de numériser le texte entier à l'aide du scanner et de parcourir le texte ligne par ligne. Bien sûr, vous devez importer les éléments suivants:
Le scanner scanne essentiellement tout le texte. La boucle while est utilisée pour parcourir tout le texte.
La
.hasNextLine()
fonction est un booléen qui renvoie true s'il y a encore plus de lignes dans le texte. La.nextLine()
fonction vous donne une ligne entière sous forme de chaîne que vous pouvez ensuite utiliser comme vous le souhaitez. EssayezSystem.out.println(line)
d'imprimer le texte.Note latérale: .txt est le texte du type de fichier.
la source
BufferedReader.readLine()
, et il a demandé la méthode la plus performante.FileReader ne vous permet pas de spécifier l'encodage, utilisez-le à la
InputStreamReader
place si vous devez le spécifier:Si vous avez importé ce fichier à partir de Windows, il peut avoir un encodage ANSI (Cp1252), vous devez donc spécifier l'encodage.
la source
J'ai documenté et testé 10 façons différentes de lire un fichier en Java , puis je les ai exécutées les unes contre les autres en les faisant lire des fichiers de test de 1 Ko à 1 Go. Voici les 3 méthodes de lecture de fichiers les plus rapides pour lire un fichier de test de 1 Go.
Notez que lors de l'exécution des tests de performances, je n'ai rien sorti sur la console car cela ralentirait vraiment le test. Je voulais juste tester la vitesse de lecture brute.
1) java.nio.file.Files.readAllBytes ()
Testé en Java 7, 8, 9. C'était globalement la méthode la plus rapide. La lecture d'un fichier de 1 Go était systématiquement un peu moins d'une seconde.
2) java.nio.file.Files.lines ()
Cela a été testé avec succès en Java 8 et 9, mais cela ne fonctionnera pas en Java 7 en raison du manque de prise en charge des expressions lambda. Il a fallu environ 3,5 secondes pour lire un fichier de 1 Go, ce qui l'a placé en deuxième position pour la lecture de fichiers plus volumineux.
3) BufferedReader
Testé pour fonctionner en Java 7, 8, 9. Cela a pris environ 4,5 secondes pour lire dans un fichier de test de 1 Go.
Vous pouvez trouver le classement complet des 10 méthodes de lecture de fichiers ici .
la source
System.out.print/println()
ici; vous supposez également que le fichier tiendra dans la mémoire dans vos deux premiers cas.En Java 7:
la source
StandardCharsets.UTF_8
pour éviter l'exception cochée dansCharset.forName("UTF-8")
Dans Java 8, il existe également une alternative à l'utilisation
Files.lines()
. Si votre source d'entrée n'est pas un fichier mais quelque chose de plus abstrait comme unReader
ou unInputStream
, vous pouvez diffuser les lignes via la méthodeBufferedReader
slines()
.Par exemple:
appellera
processLine()
pour chaque ligne d'entrée lue par leBufferedReader
.la source
Pour lire un fichier avec Java 8
la source
Vous pouvez utiliser la classe Scanner
la source
Scanner
est très bien, mais cette réponse n'inclut pas le code complet pour l'utiliser correctement.BufferedReader.readLine()
soit certainement plusieurs fois plus rapide. Si vous pensez le contraire, veuillez fournir vos raisons.Vous devez utiliser la
readLine()
méthode dansclass BufferedReader
. Créez un nouvel objet à partir de cette classe et opérez cette méthode sur lui et enregistrez-le dans une chaîne.BufferReader Javadoc
la source
La manière claire d'y parvenir,
Par exemple:
Si vous avez
dataFile.txt
sur votre répertoire actuelLa sortie comme ci-dessous,
la source
Java 9:
la source
System.getProperty("os.name").equals("Linux")
==
!Ça marche pour moi. J'espère que cela vous aidera aussi.
la source
Vous pouvez utiliser des flux pour le faire plus précisément:
la source
Je fais habituellement la routine de lecture simple:
la source
Vous pouvez utiliser ce code:
la source
En utilisant le package org.apache.commons.io , il a donné plus de performances, en particulier dans le code hérité qui utilise Java 6 et inférieur.
Java 7 a une meilleure API avec moins de gestion des exceptions et des méthodes plus utiles:
Maven
la source
Vous pouvez également utiliser Apache Commons IO :
la source
FileUtils.readLines(file)
est une méthode obsolète. En outre, la méthode appelleIOUtils.readLines
, qui utilise un BufferedReader et ArrayList. Ce n'est pas une méthode ligne par ligne, et certainement pas une méthode qui serait pratique pour lire plusieurs Go.