web-dev-qa-db-fra.com

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

J'utilise l'idiome ci-dessous depuis un certain temps maintenant. Et cela semble être 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();
    }
}
1401
OscarRyz

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 caractères de fin de ligne:

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

Pour les versions comprises entre Java 7 et 11, voici un idiome compact et robuste, encapsulé 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 les lignes de texte d'un fichier

Java 7 a ajouté une méthode pratique pour lire un fichier sous forme de lignes de texte) représentée sous la forme d'un List<String>. Cette approche est "avec perte", car les séparateurs de lignes sont supprimés à la fin de chaque ligne.

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

Java 8 a ajouté la méthode Files.lines() pour produire un Stream<String>. Encore une fois, cette méthode entraîne des pertes car les séparateurs de lignes sont supprimés. Si un IOException est rencontré lors de la lecture du fichier, il est entouré d'un UncheckedIOException , étant donné que Stream n'accepte pas les lambdas qui jettent des exceptions vérifiées.

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

Cet Stream a besoin d'un close() call; cela est mal documenté sur l'API et je suppose que beaucoup de gens ne remarquent même pas que Stream possède une méthode close(). Veillez à utiliser un bloc ARM comme indiqué.

Si vous travaillez avec une source autre qu'un fichier, vous pouvez utiliser la méthode lines() dans BufferedReader.

Utilisation de la mémoire

La première méthode, qui préserve les sauts de ligne, peut nécessiter temporairement de la mémoire, plusieurs fois la taille du fichier, car le contenu du fichier brut (un tableau d'octets) et les caractères décodés (chacun de 16 bits, même codés) sous forme de 8 bits dans le fichier) résident en mémoire en même temps. Il est plus sûr d’appliquer des fichiers dont vous savez qu’ils sont petits par rapport à la mémoire disponible.

La deuxième méthode, la lecture de lignes, est généralement plus efficace en termes de mémoire, car le tampon d'octets d'entrée pour le décodage n'a pas besoin de contenir le fichier entier. Cependant, cela ne convient toujours pas 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, qui lit un bloc de texte dans 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 pourrait être de plusieurs gigaoctets de RAM. La troisième méthode, en utilisant un Stream<String> est un moyen de le faire, si vos "enregistrements" d’entrée sont des lignes individuelles. (L'utilisation de la méthode readLine() de BufferedReader est l'équivalent procédural de cette approche.)

Encodage de caractère

Une chose qui manque à l'échantillon dans l'article d'origine est le codage de 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 classe StandardCharsets définit des constantes pour les codages requis de tous les environnements d'exécution Java:

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

La plate-forme par défaut est disponible à partir de la classe Charset elle-même:

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

Remarque: cette réponse remplace en grande partie 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é, empêchait la suppression du fichier lu jusqu'à ce que le tampon mappé soit collecté. Vous pouvez voir l'ancienne version via le lien "modifié" de cette réponse.

1424
erickson

Si vous souhaitez utiliser une bibliothèque externe, consultez Apache Commons IO (JAR de 200 Ko). Il contient une méthode org.Apache.commons.io.FileUtils.readFileToString() qui vous permet de lire un File entier dans un String avec une 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);
}
326
Willi aus Rohr

Une solution très légère 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 charset:

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 appellera scanner.close() pour vous:

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

Rappelez-vous que le constructeur Scanner peut générer un IOException. Et n'oubliez pas d'importer Java.io et Java.util.

Source: blog de Pat Niemeyer

174
Pablo Grisafi
import Java.nio.file.Files;
import Java.nio.file.Paths;

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

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

96
Jobin Joseph

Si vous recherchez une alternative ne faisant pas appel à une 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();
    }
}
76
Dónal

Guava utilise une méthode similaire à celle de Commons IOUtils, mentionnée par Willi aus Rohr:

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

// ...

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

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, voir les classes Files , CharStreams , ByteSource et CharSource dans com. google.common.io package.

67
finnw
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 "";
    }
53
user590444

Ce code normalisera les sauts de ligne, ce qui peut être ou ne pas ê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();
    }        
}
49
Jon Skeet

Si vous avez besoin d'un traitement de chaîne (traitement parallèle), Java 8 dispose de la superbe 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 les exemples JDK sample/lambda/BulkDataOperations qui peuvent être téléchargés depuis page de téléchargement Oracle Java SE 8

Un autre exemple d'un paquebot

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

S'il s'agit d'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 que les lignes soient utilisées comme liste

public static List<String> readLines(File file) throws IOException
25
Home in Time

Rassemblé toutes les façons possibles de lire le fichier sous forme de chaîne à partir d'un disque ou d'un réseau.

  • Guava: Google utilisation de 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 expression rationnelle \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 );
    }
    

  • BufferedReader en 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

25
Yash

Depuis le 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
25
leventov

Pour lire un fichier en tant que binaire et 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
Peter Lawrey

Avec Java 7, cette option est celle que je préfère 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 API Java.nio.file, qui fournit de nombreux raccourcis. Par conséquent, les bibliothèques tierces ne sont pas toujours nécessaires pour les opérations de fichiers simples.

16
Moritz Petersen

Java tente d'être extrêmement général et flexible dans tout ce qu'il fait. En conséquence, 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 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 deuxième, car il comporte le moins de dépendances.

15
Claudiu

Utilisation de JDK 8 ou supérieur:

aucune bibliothèque externe utilisée

Vous pouvez créer un nouvel objet String à partir du contenu du fichier (Utilisation des classes du package Java.nio.file]):

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

Il existe une variante 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 "meilleur" est une question de goût personnel.

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

Si vous n'avez pas accès à la classe Files, 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);
}
7
Ilya Gazman

Une solution flexible utilisant IOUtils de 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();

Cela fonctionne avec n'importe quel lecteur ou flux d'entrée (pas seulement avec des fichiers), par exemple lors de la lecture d'une URL.

4
wau
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();
}
3
Scott S. McCoy

Soyez conscient que lorsque vous utilisez fileInputStream.available(), l'entier renvoyé ne doit pas nécessairement représenter la taille réelle du fichier, mais plutôt la quantité d'octets supposée que le système doit pouvoir lire dans le flux sans bloquer l'IO. 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 est non adaptée aux codages de caractères multi-octets tels que UTF-8.

3
Henry

Vous pouvez essayer Scanner and File class, une solution de 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
jamesjara

L'utilisateur Java.nio.Files lit 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
Nitin Vavdiya

Celui-ci utilise la méthode RandomAccessFile.readFully, il semble être disponible à partir de 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
barjak

Sur une ligne (Java 8), en supposant que vous ayez un Reader:

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

En utilisant cette bibliothèque , il s’agit d’une ligne:

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

En fonction 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()]));
}
2
Muskovets

Après Ctrl + F après scanner, je pense que la solution de scanner devrait également figurer dans la liste. Dans la forme la plus facile à lire, cela ressemble à ceci:

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 plus récent (et vous devriez le faire), envisagez d'utiliser try-with-resources pour rendre le code plus facile à lire. Plus de choses proches des points qui jonchent tout. Mais c’est surtout un choix stylistique qui me semble.

Je publie ceci principalement pour des raisons d'achèvement, car si vous devez le faire beaucoup, il devrait y avoir des choses dans Java.nio.file.Files qui devraient mieux faire le travail.

Ma suggestion serait d'utiliser Files # readAllBytes (Path) pour saisir tous les octets et le transmettre à new String (byte [] Charset) pour extraire une chaîne de c'est ce que vous pouvez faire confiance. Les jeux de caractères seront méchants avec vous pendant votre vie, alors méfiez-vous de ce genre de choses maintenant.

D'autres ont donné du code et des choses, et je ne veux pas voler leur gloire. ;)

2
Haakon Løtveit

De plus, si votre fichier se trouve dans un fichier jar, 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 doit commencer par / par exemple si votre jar est

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

Ensuite, vous voulez l'invoquer comme ceci:

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

Je ne peux pas encore commenter les autres entrées, je vais donc la laisser ici.

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 toujours un défaut. Il met toujours un nouveau caractère de ligne à la fin de la chaîne, ce qui peut causer 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();
    }
}
1
Ajk

Utilisez le code:

File file = new File("input.txt");
BufferedInputStream bin = new BufferedInputStream(new FileInputStream(
                file));
byte[] buffer = new byte[(int) file.length()];
bin.read(buffer);
String fileStr = new String(buffer);

fileStr contient la sortie dans String.

0
Devram Kandhare