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();
}
}
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);
}
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
.
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.)
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.
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);
}
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
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.
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();
}
}
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.
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 "";
}
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();
}
}
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")));
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
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
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
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();
}
}
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.
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:
Votre meilleur pari est probablement le deuxième, car il comporte le moins de dépendances.
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;
}
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);
}
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);
}
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.
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();
}
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.
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!");
}
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);
}
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
}
}
}
Sur une ligne (Java 8), en supposant que vous ayez un Reader:
String sMessage = String.join("\n", reader.lines().collect(Collectors.toList()));
En utilisant cette bibliothèque , il s’agit d’une ligne:
String data = IO.from(new File("data.txt")).toString();
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()]));
}
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. ;)
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");
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();
}
}
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.