Comment créer une chaîne Java à partir du contenu d'un fichier?


1513

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

7
Quelqu'un peut-il m'expliquer d'une manière très simple ce qui est avec le NIO? Chaque fois que j'en lis, je me perds dans la nième mention de la chaîne :(
OscarRyz

7
n'oubliez pas qu'il n'est pas garanti que le séparateur de lignes dans le fichier n'est pas nécessaire de la même manière que le séparateur de lignes du système.
Henrik Paul

138
Pourriez-vous s'il vous plaît insérer enfin un essai approprié qui ferme le lecteur? Quelqu'un pourrait utiliser cet exemple et introduire un bogue dans son code.
Hans-Peter Störr

6
Le code ci-dessus a un bug d'ajout de nouveaux caractères de ligne à la dernière ligne. Cela devrait ressembler à suivre if (line = reader.readLine ())! = Null) {stringBuilder.append (line); } while (line = reader.readLine ())! = null) {stringBuilder.append (ls); stringBuilder.append (ligne); }
Deep

27
Java 7 présente byte[] Files.readAllBytes(file);à ceux qui suggèrent la solution de scanner «une ligne»: vous n'avez pas besoin de la fermer?
Val

Réponses:


1536

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:

String content = Files.readString(path, StandardCharsets.US_ASCII);

Pour les versions entre Java 7 et 11, voici un idiome compact et robuste, enveloppé dans une méthode utilitaire:

static String readFile(String path, Charset encoding) 
  throws IOException 
{
  byte[] encoded = Files.readAllBytes(Paths.get(path));
  return new String(encoded, encoding);
}

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.

List<String> lines = Files.readAllLines(Paths.get(path), encoding);

Java 8 a ajouté la Files.lines()méthode pour produire un Stream<String>. Encore une fois, cette méthode est avec perte car les séparateurs de ligne sont supprimés. Si un IOExceptionest rencontré lors de la lecture du fichier, il est enveloppé dans un UncheckedIOException, car Streamn'accepte pas les lambdas qui lèvent des exceptions vérifiées.

try (Stream<String> lines = Files.lines(path, encoding)) {
  lines.forEach(System.out::println);
}

Cela Streamnécessite un close()appel; cela est mal documenté sur l'API, et je soupçonne que beaucoup de gens ne remarquent même pas Streama une close()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 à la BufferedReaderplace.

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 la readLine()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 StandardCharsetsclasse définit quelques constantes pour les encodages requis pour tous les runtimes Java:

String content = readFile("test.txt", StandardCharsets.UTF_8);

La plate-forme par défaut est disponible dans la Charsetclasse elle - même:

String content = readFile("test.txt", Charset.defaultCharset());

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.


3
Techniquement parlant, c'est O (n) dans le temps et l'espace. Qualitativement, en raison de l'exigence d'immuabilité des chaînes, c'est assez dur sur la mémoire; temporairement, il y a deux copies des données de caractère en mémoire, plus l'espace pour les octets codés. En supposant un codage à un octet, il faudra (temporairement) 5 octets de mémoire pour chaque caractère du fichier. Puisque la question demande spécifiquement une chaîne, c'est ce que je montre, mais si vous pouvez travailler avec le CharBuffer renvoyé par "décoder", la mémoire requise est bien moindre. En termes de temps, je ne pense pas que vous trouverez quelque chose de plus rapide dans les bibliothèques Java de base.
erickson

5
Faute de frappe possible? NIO a une classe Charset (pas CharSet) appelée java.nio.charset.Charset. Est-ce que cela aurait dû être CharSet?
Jonathan Wright

31
Remarque: après avoir exercé un peu ce code, j'ai découvert que vous ne pouvez pas supprimer le fichier de manière fiable juste après l'avoir lu avec cette méthode, ce qui peut être un problème dans certains cas, mais pas le mien. Peut-il être en relation avec ce problème: bugs.sun.com/bugdatabase/view_bug.do?bug_id=4715154 ? Je suis finalement allé avec la proposition de Jon Skeet qui ne souffre pas de ce bug. Quoi qu'il en soit, je voulais juste donner l'info, pour d'autres personnes, juste au cas où ...
Sébastien Nussbaumer

5
@ Sébastien Nussbaumer: J'ai également rencontré ce problème. Étonnant que le bogue ait été marqué "ne sera pas corrigé". Cela signifie essentiellement que FileChannel#mapc'est, en général, inutilisable.
Joonas Pulakka

4
@ Sébastien Nussbaumer: Le bogue a été supprimé de la base de données de bogues Oracle / Sun: "Ce bogue n'est pas disponible." Google a mis le site en cache sur webcache.googleusercontent.com/search?q=cache:bugs.sun.com/…
bobndrew

351

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 entier Filedans unString avec une seule ligne de code.

Exemple:

import java.io.*;
import java.nio.charset.*;
import org.apache.commons.io.*;

public String readFile() throws IOException {
    File file = new File("data.txt");
    return FileUtils.readFileToString(file, StandardCharsets.UTF_8);
}

Je ne trouve pas cette méthode dans l'URL que vous fournissez.
OscarRyz

2
C'est dans la classe org.apache.commons.io.FileUtils
Cyrille Ka

2
J'utilise également FileUtils, mais je me demande ce qui est mieux entre l'utilisation de FileUtils ou la réponse nio acceptée?
Guillaume

4
@Guillaume: La plus grande question est de savoir si vous êtes à l'aise d'avoir une dépendance à l'égard d'une bibliothèque tierce. Si vous avez Commons IO ou Guava dans votre projet, utilisez-le (juste pour la simplicité du code; sinon il n'y aura probablement pas de différence notable).
Jonik

183

Une solution très allégée basée sur Scanner:

Scanner scanner = new Scanner( new File("poem.txt") );
String text = scanner.useDelimiter("\\A").next();
scanner.close(); // Put this call in a finally block

Ou, si vous souhaitez définir le jeu de caractères:

Scanner scanner = new Scanner( new File("poem.txt"), "UTF-8" );
String text = scanner.useDelimiter("\\A").next();
scanner.close(); // Put this call in a finally block

Ou, avec un bloc try-with-resources , qui scanner.close()vous demandera :

try (Scanner scanner = new Scanner( new File("poem.txt"), "UTF-8" )) {
    String text = scanner.useDelimiter("\\A").next();
}

N'oubliez pas que le Scannerconstructeur peut lancer un IOException. Et n'oubliez pas d'importer java.ioet java.util.

Source: blog de Pat Niemeyer


4
\\ A fonctionne car il n'y a pas d '"autre début de fichier", vous lisez donc le dernier jeton ... qui est aussi le premier. Jamais essayé avec \\ Z. Notez également que vous pouvez lire tout ce qui est lisible, comme les fichiers, les flux d'entrée, les canaux ... J'utilise parfois ce code pour lire à partir de la fenêtre d'affichage d'Eclipse, lorsque je ne suis pas sûr de lire un fichier ou un autre .. .oui, classpath me confond.
Pablo Grisafi

1
En tant que poster, je peux dire que je ne sais vraiment pas si et quand le fichier est correctement fermé ... Je n'écris jamais celui-ci dans le code de production, je ne l'utilise que pour les tests ou le débogage.
Pablo Grisafi

2
Il a une limite de 1024 caractères je pense
Whimusical

20
Le scanner implémente Closeable (il invoque de près la source) - donc, bien qu'élégant, il ne devrait pas vraiment être à une ligne. La taille par défaut du tampon est 1024, mais le scanner augmentera la taille si nécessaire (voir Scanner # makeSpace ())
earcam

8
Celui-ci échoue pour les fichiers vides avec un java.util.NoSuchElementException.
SpaceTrucker

117
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;

String content = new String(Files.readAllBytes(Paths.get("readMe.txt")), StandardCharsets.UTF_8);

depuis java 7, vous pouvez le faire de cette façon.


Cela devrait être accepté comme réponse - une seule ligne, pas de bibliothèques externes.
Cherry

Cela a ajouté un caractère de nouvelle ligne à la fin, même s'il n'était pas présent dans le fichier
Stefan Haberl

79

Si vous recherchez une alternative qui n'implique pas de bibliothèque tierce (par exemple, Commons I / O ), vous pouvez utiliser la classe Scanner :

private String readFile(String pathname) throws IOException {

    File file = new File(pathname);
    StringBuilder fileContents = new StringBuilder((int)file.length());        

    try (Scanner scanner = new Scanner(file)) {
        while(scanner.hasNextLine()) {
            fileContents.append(scanner.nextLine() + System.lineSeparator());
        }
        return fileContents.toString();
    }
}

2
Je pense que c'est la meilleure façon. Consultez java.sun.com/docs/books/tutorial/essential/io/scanning.html
Tarski

3
Le constructeur Scanner qui accepte une chaîne ne traite pas la chaîne comme le nom d'un fichier à lire, mais comme le texte à analyser. Je fais cette erreur tout le temps. : - /
Alan Moore

@Alan, bonne prise. J'ai légèrement modifié la réponse de Don pour corriger cela (j'espère).
Jonik

3
fileContents.append (scanner.nextLine ()). append (lineSeparator);
ban-geoengineering

1
Remplacez l'instruction d'initialisation par Scanner scanner = new Scanner((Readable) new BufferedReader(new FileReader(file)));. Sinon, vous ne pouvez capturer qu'une partie du fichier.
Wei Yang

71

La goyave a une méthode similaire à celle de Commons IOUtils que Willi aus Rohr a mentionnée:

import com.google.common.base.Charsets;
import com.google.common.io.Files;

// ...

String text = Files.toString(new File(path), Charsets.UTF_8);

EDIT by PiggyPiglet
Files#toString est obsolète et doit être supprimé en octobre 2019. Utilisez plutôt Files.asCharSource(new File(path), StandardCharsets.UTF_8).read();

EDIT par Oscar Reyes

Voici le code sous-jacent (simplifié) de la bibliothèque citée:

InputStream in = new FileInputStream(file);
byte[] b  = new byte[file.length()];
int len = b.length;
int total = 0;

while (total < len) {
  int result = in.read(b, total, len - total);
  if (result == -1) {
    break;
  }
  total += result;
}

return new String( b , Charsets.UTF_8 );

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 .


Ce code a un casting de long en int qui pourrait faire apparaître un comportement fou avec de gros fichiers. A des espaces supplémentaires et où fermez-vous le flux d'entrée?
Mohamed Taher Alrefaie

@MTA: Le flux est fermé, notez l'utilisation de Closerdans CharSource . Le code dans la réponse n'est pas la source actuelle et actuelle de la goyave.
Jonik

54
import java.nio.file.Files;

.......

 String readFile(String filename) {
            File f = new File(filename);
            try {
                byte[] bytes = Files.readAllBytes(f.toPath());
                return new String(bytes,"UTF-8");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return "";
    }

6
Ou encore plus simple:new String(Files.readAllBytes(FileSystems.getDefault().getPath( filename)));

12
ou new String(Files.readAllBytes(Paths.get(filename)));:-)
assafmo

1
Bien joué, et pour sauver le prochain gars, le googling, Pathsest apparemment 1.7+ tel quelFileSystems . (Dang it!)
ruffin

4
C'est dommage que cette réponse n'ait pas plus de votes. Je cherchais le moyen le plus rapide et le plus simple d'obtenir un fichier texte dans une chaîne. C'est ça et si je n'avais pas fait défiler de haut en bas, je l'aurais manqué. Le PO devrait envisager d'accepter cette réponse pour la déplacer vers le haut.
Thorn

@Thorn Cette réponse a horrible gestion des erreurs. N'utilisez pas cette méthode dans le code de production, ou mieux: jamais.
xehpuk

51

Si vous avez besoin d'un traitement de chaîne (traitement parallèle), Java 8 possède la grande API Stream.

String result = Files.lines(Paths.get("file.txt"))
                    .parallel() // for parallel processing 
                    .map(String::trim) // to change line   
                    .filter(line -> line.length() > 2) // to filter some lines by a predicate                        
                    .collect(Collectors.joining()); // to join lines

D'autres exemples sont disponibles dans des exemples JDK sample/lambda/BulkDataOperationsqui peuvent être téléchargés à partir de la page de téléchargement d' Oracle Java SE 8

Un autre exemple de liner

String out = String.join("\n", Files.readAllLines(Paths.get("file.txt")));

Le .parallel () se produit-il après avoir lu les lignes ou avant cela?
Istvan

Le vrai travail commence depuis que l'opération de terminal collecte (...) est invoquée. Le flux est paresseusement rempli ligne par ligne. Il n'est pas nécessaire de lire l'intégralité du fichier en mémoire avant le traitement (par exemple, filtrage et mappage).
Andrei N

couper avant de choisir des lignes non vides?
Thorbjørn Ravn Andersen

50

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):

public static String readFile(String file, String csName)
            throws IOException {
    Charset cs = Charset.forName(csName);
    return readFile(file, cs);
}

public static String readFile(String file, Charset cs)
            throws IOException {
    // No real need to close the BufferedReader/InputStreamReader
    // as they're only wrapping the stream
    FileInputStream stream = new FileInputStream(file);
    try {
        Reader reader = new BufferedReader(new InputStreamReader(stream, cs));
        StringBuilder builder = new StringBuilder();
        char[] buffer = new char[8192];
        int read;
        while ((read = reader.read(buffer, 0, buffer.length)) > 0) {
            builder.append(buffer, 0, read);
        }
        return builder.toString();
    } finally {
        // Potential issue here: if this throws an IOException,
        // it will mask any others. Normally I'd use a utility
        // method which would log exceptions and swallow them
        stream.close();
    }        
}

1
Pardonnez-moi d'avoir relancé un commentaire aussi ancien, mais vouliez-vous passer un objet String appelé "fichier", ou devrait-il plutôt être un objet File?
Bryan Larson

28

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

    static Charset charset = com.google.common.base.Charsets.UTF_8;
    public static String guava_ServerFile( URL url ) throws IOException {
        return Resources.toString( url, charset );
    }
    public static String guava_DiskFile( File file ) throws IOException {
        return Files.toString( file, charset );
    }

  • APACHE - COMMONS IO utilisant les classes IOUtils, FileUtils

    static Charset encoding = org.apache.commons.io.Charsets.UTF_8;
    public static String commons_IOUtils( URL url ) throws IOException {
        java.io.InputStream in = url.openStream();
        try {
            return IOUtils.toString( in, encoding );
        } finally {
            IOUtils.closeQuietly(in);
        }
    }
    public static String commons_FileUtils( File file ) throws IOException {
        return FileUtils.readFileToString( file, encoding );
        /*List<String> lines = FileUtils.readLines( fileName, encoding );
        return lines.stream().collect( Collectors.joining("\n") );*/
    }

  • Java 8 BufferReader utilisant Stream API

    public static String streamURL_Buffer( URL url ) throws IOException {
        java.io.InputStream source = url.openStream();
        BufferedReader reader = new BufferedReader( new InputStreamReader( source ) );
        //List<String> lines = reader.lines().collect( Collectors.toList() );
        return reader.lines().collect( Collectors.joining( System.lineSeparator() ) );
    }
    public static String streamFile_Buffer( File file ) throws IOException {
        BufferedReader reader = new BufferedReader( new FileReader( file ) );
        return reader.lines().collect(Collectors.joining(System.lineSeparator()));
    }

  • Classe de scanner avec regex \A. qui correspond au début de l'entrée.

    static String charsetName = java.nio.charset.StandardCharsets.UTF_8.toString();
    public static String streamURL_Scanner( URL url ) throws IOException {
        java.io.InputStream source = url.openStream();
        Scanner scanner = new Scanner(source, charsetName).useDelimiter("\\A");
        return scanner.hasNext() ? scanner.next() : "";
    }
    public static String streamFile_Scanner( File file ) throws IOException {
        Scanner scanner = new Scanner(file, charsetName).useDelimiter("\\A");
        return scanner.hasNext() ? scanner.next() : "";
    }

  • Java 7 ( java.nio.file.Files.readAllBytes)

    public static String getDiskFile_Java7( File file ) throws IOException {
        byte[] readAllBytes = java.nio.file.Files.readAllBytes(Paths.get( file.getAbsolutePath() ));
        return new String( readAllBytes );
    }

  • BufferedReaderen utilisant InputStreamReader.

    public static String getDiskFile_Lines( File file ) throws IOException {
        StringBuffer text = new StringBuffer();
        FileInputStream fileStream = new FileInputStream( file );
        BufferedReader br = new BufferedReader( new InputStreamReader( fileStream ) );
        for ( String line; (line = br.readLine()) != null; )
            text.append( line + System.lineSeparator() );
        return text.toString();
    }

Exemple avec la méthode principale pour accéder aux méthodes ci-dessus.

public static void main(String[] args) throws IOException {
    String fileName = "E:/parametarisation.csv";
    File file = new File( fileName );

    String fileStream = commons_FileUtils( file );
            // guava_DiskFile( file );
            // streamFile_Buffer( file );
            // getDiskFile_Java7( file );
            // getDiskFile_Lines( file );
    System.out.println( " File Over Disk : \n"+ fileStream );


    try {
        String src = "https://code.jquery.com/jquery-3.2.1.js";
        URL url = new URL( src );

        String urlStream = commons_IOUtils( url );
                // guava_ServerFile( url );
                // streamURL_Scanner( url );
                // streamURL_Buffer( url );
        System.out.println( " File Over Network : \n"+ urlStream );
    } catch (MalformedURLException e) {
        e.printStackTrace();
    }
}

@voir


26

Si c'est un fichier texte, pourquoi ne pas utiliser apache commons-io ?

Il a la méthode suivante

public static String readFileToString(File file) throws IOException

Si vous voulez les lignes comme liste, utilisez

public static List<String> readLines(File file) throws IOException

25

Depuis JDK 11:

String file = ...
Path path = Paths.get(file);
String content = Files.readString(path);
// Or readString(path, someCharset), if you need a Charset different from UTF-8

Pourquoi, oh pourquoi, introduire de nouvelles méthodes qui s'appuient sur le jeu de caractères par défaut en 2018?
mryan

2
@mryan cette méthode ne repose pas sur le jeu de caractères système par défaut. Il est par défaut UTF-8, c'est très bien.
leventov

@leventov vous avez raison! Files.readAllLines aussi! cela rend les fichiers API peu cohérents avec les anciennes méthodes mais c'est pour le mieux :)
mryan

17

Pour lire un fichier au format binaire et le convertir à la fin

public static String readFileAsString(String filePath) throws IOException {
    DataInputStream dis = new DataInputStream(new FileInputStream(filePath));
    try {
        long len = new File(filePath).length();
        if (len > Integer.MAX_VALUE) throw new IOException("File "+filePath+" too large, was "+len+" bytes.");
        byte[] bytes = new byte[(int) len];
        dis.readFully(bytes);
        return new String(bytes, "UTF-8");
    } finally {
        dis.close();
    }
}

16

Avec Java 7, c'est mon option préférée pour lire un fichier UTF-8:

String content = new String(Files.readAllBytes(Paths.get(filename)), "UTF-8");

Depuis Java 7, le JDK dispose de la nouvelle java.nio.fileAPI, 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.


15

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:

  • Utilisez une bibliothèque externe.
  • Copiez ce code dans tous vos projets.
  • Créez votre propre mini-bibliothèque contenant les fonctions que vous utilisez souvent.

Votre meilleur pari est probablement le 2ème, car il a le moins de dépendances.


4
Ouais. Cela fait que le langage de «haut» niveau prend un sens différent. Java est de haut niveau par rapport à C mais faible par rapport à Python ou Ruby
OscarRyz

3
Convenez que Java est long sur les abstractions de haut niveau mais court sur les méthodes pratiques
Dónal

3
Certes, Java a un nombre fou de façons de traiter les fichiers et beaucoup d'entre elles semblent compliquées. Mais cela est assez proche de ce que nous avons dans les langues de niveau supérieur:byte[] bytes = Files.readAllBytes(someFile.toPath());
Thorn

11

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.filepackage):

public String readStringFromFile(String filePath) throws IOException {
    String fileContent = new String(Files.readAllBytes(Paths.get(filePath)));
    return fileContent;
}

Duplicata de Moritz Petersen qui a écrit: String content = new String (Files.readAllBytes (Paths.get (filename)), "UTF-8");
Jean-Christophe Blanchard

8

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.

for(String line = reader.readLine(); line != null; line = reader.readLine()) {
    stringBuilder.append(line);
    stringBuilder.append(ls);
}

3
Cela changera les retours à la ligne par défaut. Cela peut être souhaitable ou involontaire.
Peter Lawrey

Annulé la modification de cette réponse car il s'agissait de restreindre la portée de la linevariable. L'édition l'a déclaré deux fois, ce qui serait une erreur de compilation.
Dan Dyer

7

Si vous n'avez pas accès à la Filesclasse, vous pouvez utiliser une solution native.

static String readFile(File file, String charset)
        throws IOException
{
    FileInputStream fileInputStream = new FileInputStream(file);
    byte[] buffer = new byte[fileInputStream.available()];
    int length = fileInputStream.read(buffer);
    fileInputStream.close();
    return new String(buffer, 0, length, charset);
}

exemple charset à invoquer?
Thufir

4

Une solution flexible utilisant IOUtils d'Apache commons-io en combinaison avec StringWriter :

Reader input = new FileReader();
StringWriter output = new StringWriter();
try {
  IOUtils.copy(input, output);
} finally {
  input.close();
}
String fileContents = output.toString();

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.


3

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 à ceci

public String readStringFromInputStream(FileInputStream fileInputStream) {
    StringBuffer stringBuffer = new StringBuffer();
    try {
        byte[] buffer;
        while (fileInputStream.available() > 0) {
            buffer = new byte[fileInputStream.available()];
            fileInputStream.read(buffer);
            stringBuffer.append(new String(buffer, "ISO-8859-1"));
        }
    } catch (FileNotFoundException e) {
    } catch (IOException e) { }
    return stringBuffer.toString();
}

Il convient de considérer que cette approche ne convient pas aux codages de caractères multi-octets comme UTF-8.


1
Ce code peut donner des résultats imprévisibles. Selon la documentation de la 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 par available(), auquel cas vous obtenez une sortie corrompue.
wau

3

Celui-ci utilise la méthode RandomAccessFile.readFully, il semble être disponible depuis JDK 1.0!

public static String readFileContent(String filename, Charset charset) throws IOException {
    RandomAccessFile raf = null;
    try {
        raf = new RandomAccessFile(filename, "r");
        byte[] buffer = new byte[(int)raf.length()];
        raf.readFully(buffer);
        return new String(buffer, charset);
    } finally {
        closeStream(raf);
    }
} 


private static void closeStream(Closeable c) {
    if (c != null) {
        try {
            c.close();
        } catch (IOException ex) {
            // do nothing
        }
    }
}

3

Vous pouvez essayer Scanner and File class, une solution en quelques lignes

 try
{
  String content = new Scanner(new File("file.txt")).useDelimiter("\\Z").next();
  System.out.println(content);
}
catch(FileNotFoundException e)
{
  System.out.println("not found!");
}

3

L'utilisateur java.nio.Filesdoit lire toutes les lignes du fichier.

public String readFile() throws IOException {
        File fileToRead = new File("file path");
        List<String> fileLines = Files.readAllLines(fileToRead.toPath());
        return StringUtils.join(fileLines, StringUtils.EMPTY);
}

3
public static String slurp (final File file)
throws IOException {
    StringBuilder result = new StringBuilder();

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

    try {
        char[] buf = new char[1024];

        int r = 0;

        while ((r = reader.read(buf)) != -1) {
            result.append(buf, 0, r);
        }
    }
    finally {
        reader.close();
    }

    return result.toString();
}

Je pense que cela a l'inconvénient d'utiliser le codage par défaut de la plate-forme. +1 quand même :)
OscarRyz

7
Il me semble que le bloc finally ne connaît pas les variables définies dans le bloc try. javac 1.6.0_21 renvoie l'erreur cannot find symbol.
ceving

Avez-vous même essayé votre propre code? Vous avez défini le lecteur dans le bloc try / catch, il ne sera donc pas accessible dans le bloc finally.
mauron85

2

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 ):

private String readFile(String pathname) throws IOException {

File file = new File(pathname);
StringBuilder fileContents = new StringBuilder((int)file.length());
Scanner scanner = new Scanner(file);
String lineSeparator = System.getProperty("line.separator");

try {
    while(scanner.hasNextLine()) {        
        fileContents.append(scanner.nextLine() + lineSeparator);
    }
    return fileContents.toString();
} finally {
    scanner.close();
}
}

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:

    private String readFile(String pathname) throws IOException {
    File file = new File(pathname);
    StringBuilder fileContents = new StringBuilder((int) file.length());
    Scanner scanner = new Scanner(new BufferedReader(new FileReader(file)));
    String lineSeparator = System.getProperty("line.separator");

    try {
        if (scanner.hasNextLine()) {
            fileContents.append(scanner.nextLine());
        }
        while (scanner.hasNextLine()) {
            fileContents.append(lineSeparator + scanner.nextLine());
        }
        return fileContents.toString();
    } finally {
        scanner.close();
    }
}

Dans le premier cas, vous pourriez ajouter une nouvelle ligne supplémentaire à la fin. dans le second cas, vous pourriez en omettre un. Les deux se trompent donc également. Voir cet article
Patrick Parker

2

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:

public String fileToString(File file, Charset charset) {
  Scanner fileReader = new Scanner(file, charset);
  fileReader.useDelimiter("\\Z"); // \Z means EOF.
  String out = fileReader.next();
  fileReader.close();
  return out;
}

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. ;)


2

En utilisant cette bibliothèque , c'est une ligne:

String data = IO.from(new File("data.txt")).toString();

1
si les lignes à l'intérieur de la bibliothèque ne sont pas comptées.
Ari

2

De plus, si votre fichier se trouve dans un bocal, vous pouvez également utiliser ceci:

public String fromFileInJar(String path) {
    try ( Scanner scanner 
            = new Scanner(getClass().getResourceAsStream(path))) {
        return scanner.useDelimiter("\\A").next();
    }
}

Le chemin devrait commencer par / exemple si votre pot est

my.jar/com/some/thing/a.txt

Ensuite, vous voulez l'invoquer comme ceci:

String myTxt = fromFileInJar("/com/com/thing/a.txt");

2

En une seule ligne (Java 8), en supposant que vous avez un Reader:

String sMessage = String.join("\n", reader.lines().collect(Collectors.toList()));

2

Sur la base de la réponse de @ erickson, vous pouvez utiliser:

public String readAll(String fileName) throws IOException {
    List<String> lines = Files.readAllLines(new File(fileName).toPath());
    return String.join("\n", lines.toArray(new String[lines.size()]));
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.