J'utilise l'idiome ci-dessous depuis un certain temps maintenant. Et il semble que ce soit le plus répandu, du moins sur les sites que j'ai visités.
Existe-t-il une manière meilleure / différente de lire un fichier dans une chaîne en Java?
private String readFile(String file) throws IOException {
BufferedReader reader = new BufferedReader(new FileReader (file));
String line = null;
StringBuilder stringBuilder = new StringBuilder();
String ls = System.getProperty("line.separator");
try {
while((line = reader.readLine()) != null) {
stringBuilder.append(line);
stringBuilder.append(ls);
}
return stringBuilder.toString();
} finally {
reader.close();
}
}
byte[] Files.readAllBytes(file);
à ceux qui suggèrent la solution de scanner «une ligne»: vous n'avez pas besoin de la fermer?Réponses:
Lire tout le texte d'un fichier
Java 11 a ajouté la méthode readString () pour lire les petits fichiers en tant que
String
, en préservant les terminateurs de ligne:Pour les versions entre Java 7 et 11, voici un idiome compact et robuste, enveloppé dans une méthode utilitaire:
Lire des lignes de texte à partir d'un fichier
Java 7 a ajouté une méthode pratique pour lire un fichier sous forme de lignes de texte, représentées par un
List<String>
. Cette approche est "avec perte" car les séparateurs de ligne sont retirés de la fin de chaque ligne.Java 8 a ajouté la
Files.lines()
méthode pour produire unStream<String>
. Encore une fois, cette méthode est avec perte car les séparateurs de ligne sont supprimés. Si unIOException
est rencontré lors de la lecture du fichier, il est enveloppé dans unUncheckedIOException
, carStream
n'accepte pas les lambdas qui lèvent des exceptions vérifiées.Cela
Stream
nécessite unclose()
appel; cela est mal documenté sur l'API, et je soupçonne que beaucoup de gens ne remarquent même pasStream
a uneclose()
méthode. Assurez-vous d'utiliser un bloc ARM comme indiqué.Si vous travaillez avec une source autre qu'un fichier, vous pouvez utiliser la
lines()
méthode dans à laBufferedReader
place.Utilisation de la mémoire
La première méthode, qui préserve les sauts de ligne, peut temporairement nécessiter de la mémoire plusieurs fois la taille du fichier, car pendant une courte période le contenu brut du fichier (un tableau d'octets) et les caractères décodés (chacun de 16 bits même s'il est codé comme 8 bits dans le fichier) résident en mémoire à la fois. Il est plus sûr d'appliquer aux fichiers que vous savez être petits par rapport à la mémoire disponible.
La deuxième méthode, la lecture des lignes, est généralement plus efficace en mémoire, car le tampon d'octets d'entrée pour le décodage n'a pas besoin de contenir le fichier entier. Cependant, il n'est toujours pas adapté aux fichiers très volumineux par rapport à la mémoire disponible.
Pour lire des fichiers volumineux, vous avez besoin d'une conception différente pour votre programme, une qui lit un morceau de texte à partir d'un flux, le traite, puis passe au suivant, en réutilisant le même bloc de mémoire de taille fixe. Ici, "grand" dépend des spécifications de l'ordinateur. De nos jours, ce seuil peut être de plusieurs gigaoctets de RAM. La troisième méthode, en utilisant un,
Stream<String>
est une façon de le faire, si vos «enregistrements» d'entrée se trouvent être des lignes individuelles. (En utilisant lareadLine()
méthode deBufferedReader
est l'équivalent procédural de cette approche.)Encodage de caractère
Une chose qui manque dans l'exemple de l'article d'origine est l'encodage des caractères. Il y a des cas spéciaux où la plate-forme par défaut est ce que vous voulez, mais ils sont rares, et vous devriez pouvoir justifier votre choix.
La
StandardCharsets
classe définit quelques constantes pour les encodages requis pour tous les runtimes Java:La plate-forme par défaut est disponible dans la
Charset
classe elle - même:Remarque: Cette réponse remplace largement ma version Java 6. L'utilitaire de Java 7 simplifie le code en toute sécurité et l'ancienne réponse, qui utilisait un tampon d'octets mappés, empêchait la suppression du fichier lu jusqu'à ce que le tampon mappé soit récupéré. Vous pouvez voir l'ancienne version via le lien "édité" sur cette réponse.
la source
FileChannel#map
c'est, en général, inutilisable.Si vous souhaitez utiliser une bibliothèque externe, consultez Apache Commons IO (200KB JAR). Il contient une
org.apache.commons.io.FileUtils.readFileToString()
méthode qui vous permet de lire un entierFile
dans unString
avec une seule ligne de code.Exemple:
la source
Une solution très allégée basée sur
Scanner
:Ou, si vous souhaitez définir le jeu de caractères:
Ou, avec un bloc try-with-resources , qui
scanner.close()
vous demandera :N'oubliez pas que le
Scanner
constructeur peut lancer unIOException
. Et n'oubliez pas d'importerjava.io
etjava.util
.Source: blog de Pat Niemeyer
la source
java.util.NoSuchElementException
.depuis java 7, vous pouvez le faire de cette façon.
la source
Si vous recherchez une alternative qui n'implique pas de bibliothèque tierce (par exemple, Commons I / O ), vous pouvez utiliser la classe Scanner :
la source
Scanner scanner = new Scanner((Readable) new BufferedReader(new FileReader(file)));
. Sinon, vous ne pouvez capturer qu'une partie du fichier.La goyave a une méthode similaire à celle de Commons IOUtils que Willi aus Rohr a mentionnée:
EDIT by PiggyPiglet
Files#toString
est obsolète et doit être supprimé en octobre 2019. Utilisez plutôtFiles.asCharSource(new File(path), StandardCharsets.UTF_8).read();
EDIT par Oscar Reyes
Voici le code sous-jacent (simplifié) de la bibliothèque citée:
Edit (par Jonik): Ce qui précède ne correspond pas au code source des versions récentes de Guava. Pour la source actuelle, consultez les classes Files , CharStreams , ByteSource et CharSource dans le package com.google.common.io .
la source
Closer
dans CharSource . Le code dans la réponse n'est pas la source actuelle et actuelle de la goyave........
la source
new String(Files.readAllBytes(FileSystems.getDefault().getPath( filename)));
new String(Files.readAllBytes(Paths.get(filename)));
:-)Paths
est apparemment 1.7+ tel quelFileSystems
. (Dang it!)Si vous avez besoin d'un traitement de chaîne (traitement parallèle), Java 8 possède la grande API Stream.
D'autres exemples sont disponibles dans des exemples JDK
sample/lambda/BulkDataOperations
qui peuvent être téléchargés à partir de la page de téléchargement d' Oracle Java SE 8Un autre exemple de liner
la source
Ce code normalisera les sauts de ligne, ce qui peut ou non être ce que vous voulez vraiment faire.
Voici une alternative qui ne fait pas cela, et qui est (IMO) plus simple à comprendre que le code NIO (bien qu'il utilise toujours
java.nio.charset.Charset
):la source
Rassemblé toutes les façons possibles de lire le fichier sous forme de chaîne à partir du disque ou du réseau.
Goyave: Google utilise des classes
Resources
,Files
APACHE - COMMONS IO utilisant les classes IOUtils, FileUtils
Java 8 BufferReader utilisant Stream API
Classe de scanner avec regex
\A
. qui correspond au début de l'entrée.Java 7 (
java.nio.file.Files.readAllBytes
)BufferedReader
en utilisantInputStreamReader
.Exemple avec la méthode principale pour accéder aux méthodes ci-dessus.
@voir
la source
Si c'est un fichier texte, pourquoi ne pas utiliser apache commons-io ?
Il a la méthode suivante
Si vous voulez les lignes comme liste, utilisez
la source
Depuis JDK 11:
la source
Pour lire un fichier au format binaire et le convertir à la fin
la source
Avec Java 7, c'est mon option préférée pour lire un fichier UTF-8:
Depuis Java 7, le JDK dispose de la nouvelle
java.nio.file
API, qui fournit de nombreux raccourcis, de sorte que les bibliothèques tierces ne sont pas toujours nécessaires pour les opérations de fichiers simples.la source
Java tente d'être extrêmement général et flexible dans tout ce qu'il fait. Par conséquent, quelque chose qui est relativement simple dans un langage de script (votre code serait remplacé par "
open(file).read()
" en python) est beaucoup plus compliqué. Il ne semble pas y avoir de moyen plus court de le faire, sauf en utilisant une bibliothèque externe (comme Willi aus Rohr l'a mentionné). Vos options:Votre meilleur pari est probablement le 2ème, car il a le moins de dépendances.
la source
byte[] bytes = Files.readAllBytes(someFile.toPath());
En utilisant JDK 8 ou supérieur:
aucune bibliothèque externe utilisée
Vous pouvez créer un nouvel objet String à partir du contenu du fichier (à l'aide des classes du
java.nio.file
package):la source
Il existe une variation sur le même thème qui utilise une boucle for, au lieu d'une boucle while, pour limiter la portée de la variable de ligne. Que ce soit "mieux" est une question de goût personnel.
la source
line
variable. L'édition l'a déclaré deux fois, ce qui serait une erreur de compilation.Si vous n'avez pas accès à la
Files
classe, vous pouvez utiliser une solution native.la source
Une solution flexible utilisant IOUtils d'Apache commons-io en combinaison avec StringWriter :
Il fonctionne avec n'importe quel lecteur ou flux d'entrée (pas seulement avec des fichiers), par exemple lors de la lecture à partir d'une URL.
la source
Soyez conscient lorsque l'utilisation de
fileInputStream.available()
l'entier renvoyé ne doit pas représenter la taille réelle du fichier, mais plutôt la quantité supposée d'octets que le système devrait pouvoir lire à partir du flux sans bloquer les E / S. Un moyen simple et sûr pourrait ressembler à ceciIl convient de considérer que cette approche ne convient pas aux codages de caractères multi-octets comme UTF-8.
la source
available()
méthode, il n'y a aucune garantie que la fin du fichier est atteinte dans le cas où la méthode renvoie 0. Dans ce cas, vous pourriez vous retrouver avec un fichier incomplet. Pire encore, le nombre d'octets réellement lus peut être inférieur à la valeur renvoyée paravailable()
, auquel cas vous obtenez une sortie corrompue.Celui-ci utilise la méthode
RandomAccessFile.readFully
, il semble être disponible depuis JDK 1.0!la source
Vous pouvez essayer Scanner and File class, une solution en quelques lignes
la source
L'utilisateur
java.nio.Files
doit lire toutes les lignes du fichier.la source
la source
cannot find symbol
.Je ne peux pas encore commenter d'autres entrées, je vais donc le laisser ici.
L'une des meilleures réponses ici ( https://stackoverflow.com/a/326448/1521167 ):
a encore un défaut. Il met toujours un nouveau caractère de ligne à la fin de la chaîne, ce qui peut provoquer des bugs étranges. Ma suggestion est de le changer en:
la source
Après Ctrl + F après Scanner, je pense que la solution Scanner devrait aussi être listée. De la manière la plus facile à lire, cela se passe comme suit:
Si vous utilisez Java 7 ou une version plus récente (et vous devriez vraiment le faire), envisagez d'utiliser try-with-resources pour faciliter la lecture du code. Plus de trucs étroits qui jonchent tout. Mais c'est surtout un choix stylistique.
Je poste cela principalement pour l'achèvement, car si vous avez besoin de faire beaucoup de choses, il devrait y avoir des choses dans java.nio.file.Files qui devraient faire le travail mieux.
Ma suggestion serait d'utiliser Files # readAllBytes (Path) pour récupérer tous les octets et de le nourrir dans une nouvelle chaîne (byte [] Charset) pour en extraire une chaîne en laquelle vous pouvez avoir confiance. Les jeux de caractères seront méchants pour vous au cours de votre vie, alors méfiez-vous de ce genre de choses maintenant.
D'autres ont donné du code et des trucs, et je ne veux pas voler leur gloire. ;)
la source
En utilisant cette bibliothèque , c'est une ligne:
la source
De plus, si votre fichier se trouve dans un bocal, vous pouvez également utiliser ceci:
Le chemin devrait commencer par
/
exemple si votre pot estEnsuite, vous voulez l'invoquer comme ceci:
la source
En une seule ligne (Java 8), en supposant que vous avez un Reader:
la source
Sur la base de la réponse de @ erickson, vous pouvez utiliser:
la source