Historiquement, le traitement des entrées / sorties de fichiers par Java était réputé pour sa lourdeur. Le traitement des entrées / sorties de fichiers de Java était souvent la cible d'attaques lorsque le camp du langage de script faisait appel à sa «productivité» élevée. On dit que le traitement qui peut être réalisé en quelques lignes dans un langage de script devient des dizaines de lignes en Java.
Le temps a passé et la situation s'est considérablement améliorée avec le package java.nio.file
(API de fichier NIO2) et la syntaxe try-with-resources introduits dans Java 7 en 2011. Désormais, même Java peut réaliser un traitement d'entrée / sortie de fichier avec la même quantité de code que le langage de script.
Cependant, dans les articles qui recherchent «entrée / sortie de fichier Java» et atteignent le sommet, seul le code inapproprié qui utilise uniquement l'API avant l'introduction de l'amélioration ci-dessus est remarquable. Par conséquent, dans cet article, je voudrais résumer systématiquement et de manière concise le traitement d'entrée / sortie de fichier Java le plus simple que les débutants devraient connaître pour le moment, quel que soit le contexte historique du passé.
L'interface java.nio.file.Path
(référence: Javadoc est utilisée pour représenter le chemin du système de fichiers. /Path.html)) est utilisé. Il existe différentes manières de créer une instance Path, mais en réalité, la classe utilitaire java.nio.file.Paths
(Référence: Javadoc Généré principalement à l'aide de java / nio / file / Paths.html)).
Path path = Paths.get("items.csv");
Vous pouvez spécifier la chaîne de chemin comme chemin relatif ou chemin absolu.
Path path = Paths.get("/etc/passwd");
Compte tenu du mode de portabilité des chaînes séparées par des chemins, il est préférable d'utiliser cette méthode d'argument de longueur variable.
Path path = Paths.get("/etc", "passwd");
À partir de Java 11, la méthode Path.of (String)
a été introduite en plus de la méthode Paths.get (String)
(Référence: Javadoc javase / 11 / docs / api / java.base / java / nio / file / Path.html # of (java.lang.String, java.lang.String ...))). La fonction est la même, mais celle-ci est plus cohérente avec List.of ()
Map.of ()
etc., qui a également été introduite dans Java 11, et est naturelle.
Path path = Path.of("items.csv");
Le traitement lié aux fichiers est effectué avec l'interface Path
et la classe utilitaire java.nio.file.Files
(Référence: Javadoc Combinez nio / file / Files.html)). Par exemple, cela ressemble à ceci.
List<String> lines = Files.readAllLines(Paths.get("items.csv"));
La classe qui représente un fichier en Java est java.io.File
(Référence: Javadoc )) Vous pourriez y penser. Il s'agit d'une méthode plus ancienne et peut être remplacée par la fonctionnalité du package java.nio.file
. Notez que si l'ancienne API n'accepte que java.io.File
au lieu de java.nio.file.Path
, vous pouvez effectuer une conversion entrePath # toFile ()
etFile # toPath ()
.
Dans cet article, nous n'entrerons pas dans les détails de ce qu'est un binaire de texte, mais simplement lire et écrire des fichiers de type String
du point de vue de Java sont appelés fichiers texte.
Le moyen le plus simple de lire du texte est d'utiliser la méthode Files.readString (Path)
. Cette méthode retourne tout le contenu du fichier sous forme de chaîne.
String content = Files.readString(Paths.get("items.csv"));
Vous devez faire attention au jeu de caractères lors de la lecture et de l'écriture de texte. Le code ci-dessus ne spécifie pas de jeu de caractères, donc l'UTF-8 par défaut est utilisé. La méthode de spécification du jeu de caractères est indiquée ci-dessous.
String content = Files.readString(Paths.get("items.csv"), StandardCharsets.UTF_8);
String content = Files.readString(Paths.get("items.csv"), Charset.forName("MS932"));
Eh bien, voici une mauvaise nouvelle. La méthode Files.readString (Path)
Files.readString (Path, Charset)
décrite ci-dessus n'est disponible que dans Java 11 et supérieur. Voici une autre façon de l'utiliser à partir de java 7. Cette méthode renvoie le contenu du fichier sous le type List <String>
.
List<String> lines = Files.readAllLines(Paths.get("items.csv"), StandardCharsets.UTF_8);
Si la taille du fichier est petite, vous pouvez les lire tous en même temps comme décrit ci-dessus. Cependant, si vous avez la possibilité de traiter des fichiers de plus de dizaines ou de centaines de mégaoctets, vous devez vous rappeler comment les gérer avec Stream <String>
ici. Cette méthode a de meilleures performances.
try (Stream<String> lines = Files.lines(Paths.get("items.csv"), StandardCharsets.UTF_8)) {
lines.forEach(line -> System.out.println(line));
} catch (IOException e) {
throw new UncheckedIOException(e);
}
Lorsque vous utilisez cette méthode, utilisez la syntaxe try-with-resources pour éviter d'oublier de fermer. Il en va de même pour la lecture et l'écriture d'autres subdivisions. Voir Compréhension étape par étape de la gestion des exceptions Java pour plus de détails.
De plus, si vous avez besoin de lire du texte subdivisé qui n'est pas orienté ligne, java.io.BufferedReader
est renvoyé de Files.newBufferedReader (Path, Charset)
(Référence: Javadoc Utilisez com / javase / jp / 8 / docs / api / java / io / BufferedReader.html)). Si vous souhaitez lire un énorme fichier JSON sans saut de ligne, vous aurez besoin de cette méthode.
try (BufferedReader in = Files.newBufferedReader(Paths.get("items.csv"), StandardCharsets.UTF_8)) {
for (int ch = 0; (ch = in.read()) > 0;) {
System.out.print((char) ch);
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
Abstraction supplémentaire en combinaison avec java.util.Scanner
(Référence: Javadoc) Une API élevée peut être utilisée.
try (BufferedReader in = Files.newBufferedReader(Paths.get("items.csv"), StandardCharsets.UTF_8);
Scanner sc = new Scanner(in)) {
sc.useDelimiter("(,|\\n)");
while (sc.hasNext()) {
System.out.println(sc.next());
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
Le moyen le plus simple d'écrire du texte est d'utiliser la méthode Files.writeString (Path, CharSequence, OpenOption ...)
. Cette méthode écrit tout le contenu de la "CharSequence" donnée dans un fichier. De plus, String
et StringBuilder
sont une sorte de CharSequence
(Référence: [Javadoc](https://docs.oracle.com/javase/jp/8/docs/api/java/lang/CharSequence. html)).
String content = "0-0\t0-1\t0-2\n1-0\t1-1\t1-2\n";
Files.writeString(Paths.get("items.tsv"), content);
Vous pouvez l'ajouter en définissant ʻOpenOption`.
String content = "0-0\t0-1\t0-2\n1-0\t1-1\t1-2\n";
Files.writeString(Paths.get("items.tsv"), content, StandardOpenOption.APPEND);
Vous pouvez spécifier le jeu de caractères ici ainsi que lors de la lecture.
String content = "0-0\t0-1\t0-2\n1-0\t1-1\t1-2\n";
Files.writeString(Paths.get("items.tsv"), content, StandardCharsets.UTF_8);
String content = "0-0\t0-1\t0-2\n1-0\t1-1\t1-2\n";
Files.writeString(Paths.get("items.tsv"), content, Charset.forName("MS932"));
Maintenant, voici une autre malheureuse nouvelle. La méthode ci-dessus Files.writeString (Path, CharSequence, OpenOption ...)
Files.writeString (Path, CharSequence, Charset, OpenOption ...)
est uniquement disponible dans Java 11 et supérieur. Avant cela, vous ne pouvez utiliser que la même méthode que l'écriture par petits morceaux.
Lors de l'écriture de texte en petits morceaux, java.io.BufferedWriter
renvoyé de Files.newBufferedWriter (Chemin, Jeu de caractères, OpenOption ...)
(Référence: Javadoc /jp/8/docs/api/java/io/BufferedWriter.html)) est utilisé.
List<String> lines = new ArrayList<String>();
...
try (BufferedWriter out = Files.newBufferedWriter(Paths.get("items.tsv"), StandardCharsets.UTF_8)) {
for (String line : lines) {
out.write(line);
out.newLine();
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
Dans cet article, un fichier qui est simplement lu et écrit sous forme de chaîne d'octets du point de vue de Java est appelé un fichier binaire.
La méthode la plus simple pour lire un binaire est la méthode Files.readBytes (Path)
. Cette méthode renvoie tout le contenu du fichier sous la forme byte []
.
byte[] content = Files.readAllBytes(Paths.get("selfie.jpg "));
Pour référence, la méthode de conversion de «byte []» en «String» ou «java.io.InputStream» est indiquée ci-dessous. Une telle conversion est nécessaire en fonction de la commodité de l'API à laquelle le binaire chargé est passé.
byte[] content = Files.readAllBytes(Paths.get("items.csv"));
String contentAsString = new String(content, StandardCharsets.UTF_8);
byte[] content = Files.readAllBytes(Paths.get("selfie.jpg "));
InputStream in = new ByteArrayInputStream(content);
Comme pour le texte, le chargement en masse n'est pas recommandé pour les fichiers de grande taille. À la place, la méthode Files.newInputStream (Path, OpenOption ...)
renvoie java.io.InputStream
(Référence: Javadoc Utilisez /api/java/io/InputStream.html)). En ce qui concerne le java.io.InputStream
acquis, il y a plus de cas où il est traité par une bibliothèque existante que lorsqu'il est traité en boucle seul. À titre d'exemple, le code suivant le transmet à Apache POI.
try (InputStream in = Files.newInputStream(Paths.get("items.xlsx"))) {
XSSFWorkbook book = new XSSFWorkbook(in);
...
} catch (IOException e) {
throw new UncheckedIOException(e);
}
La méthode la plus simple pour écrire un binaire est la méthode Files.write (Path, byte [], OpenOption ...)
.
byte[] content = ...;
Files.write(Paths.get("selfie.jpg "), content);
Lors de l'écriture d'un binaire en petits morceaux, java.io.OutputStream
renvoyé de Files.newOutputStream (Chemin, OpenOption ...)
(Référence: Javadoc / 8 / docs / api / java / io / OutputStream.html))) est utilisé. Il y aura plus de cas où la bibliothèque existante gère cela également, plutôt que de le gérer vous-même. À titre d'exemple, le code suivant le transmet à Apache POI.
Item item = ...;
try (OutputStream out = Files.newOutputStream(Paths.get("items.xlsx"))) {
XSSFWorkbook book = new XSSFWorkbook();
...
book.write(out);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
Vous trouverez ci-dessous un exemple de code courant à l'époque où il n'y avait ni NIO2 File API ni try-with-resources. Certes, c'est une complexité dont on ne peut se plaindre même si elle est attaquée par le camp du langage script. En ce qui concerne la partie try-catch en plusieurs étapes, "Initialement, si vous fermez BufferedReader
, le ʻInputStream inférieur sera également fermé, mais si vous ne parvenez pas à initialiser
BufferedReader`, une fuite de ressources peut se produire. Je me souviens qu'il y avait un argument du genre "Il est nécessaire pour ...". J'ai oublié les détails et je ne pense plus avoir besoin de m'en souvenir.
String content = null;
InputStream is = null;
try {
is = new FileInputStream("items.csv");
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = br.readLine()) != null) {
sb.append(line);
sb.append(System.lineSeparator());
}
content = sb.toString();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
if (br != null) {
br.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
} catch (IOException e) {
new RuntimeException(e);
} finally {
try {
if (is != null) {
is.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
Encore une fois, ce que vous essayez de faire avec le code ci-dessus peut maintenant être réalisé avec:
String content = Files.readString(Paths.get("items.csv"));
Recommended Posts