Traitement d'entrée / sortie de fichier Java pouvant être utilisé via l'historique

introduction

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é.

Connaissances préalables

Représentation du chemin

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

Principes de base du traitement de fichiers

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

(Référence) Relation avec java.io.File

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

Traitement des fichiers texte

Qu'est-ce qu'un fichier texte?

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.

Lecture de texte en masse

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

Lire le texte subdivisé

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

Rédaction de texte en masse

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.

Rédaction de texte subdivisé

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

Traitement des fichiers binaires

Qu'est-ce qu'un fichier binaire?

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.

Lecture binaire en masse

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

Lecture binaire subdivisée

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

Écriture binaire en masse

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

Écriture binaire subdivisée

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

(Référence) Ancien style d'écriture compliqué

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

Traitement d'entrée / sortie de fichier Java pouvant être utilisé via l'historique
Outil d'analyse statique pouvant être utilisé avec GitHub [version Java]
Résumé de l'ORM "uroboroSQL" qui peut être utilisé dans le Java d'entreprise
[Android Studio] Description qui peut être saisie en continu dans la base de données SQLite [Java]
[Java 8] Jusqu'à la conversion de l'entrée standard qui peut être utilisée dans les tests de codage en une liste ou un tableau
Écrivons l'entrée / sortie de fichier Java avec NIO
Extrait technologique pouvant être utilisé pour créer des sites EC dans la formation Java
Organiser les méthodes qui peuvent être utilisées avec StringUtils
Exemple de programme d'entrée / sortie de fichier Java (jdk1.8 ou version ultérieure)
Ecrire une classe qui peut être ordonnée en Java Un petit mémo standard
Le traitement Java 8 Stream peut être omis jusqu'à présent!
À propos du problème que hidden_field peut être utilisé de manière insensée
Touches de raccourci pratiques pour Eclipse
Syntaxe et conditions d'occurrence d'exception pouvant être utilisées lors de la comparaison avec null en Java
[Java 8] Méthode de tri par ordre alphabétique et par ordre de longueur de chaîne de caractères pouvant être utilisée dans les tests de codage
Créer un contrôle de page qui peut être utilisé avec RecyclerView
Créez un fichier jar qui peut être exécuté sur Gradle
Base de données Firebase-Realtime sur Android pouvant être utilisée avec copie
Problèmes facilement confondus avec Java et JavaScript
Java (édition super débutante) compréhensible en 180 secondes
Nouvelles fonctionnalités de Java 14 pouvant être utilisées pour écrire du code
Si les options peuvent être utilisées en raison des différentes versions de Java
Mémo de référence / serveur LDAP en mémoire pouvant être intégré à Java
Notez que les propriétés système, y compris JAXBContext, ne peuvent pas être utilisées dans Java11
J'ai posé une question qui peut être utilisée pour des entretiens techniques
Compétences de puissance qui peuvent être utilisées rapidement à tout moment - Réflexion
SwiftUI View qui peut être utilisé en combinaison avec d'autres frameworks
[Spring Boot] Liste des règles de validation qui peuvent être utilisées dans le fichier de propriétés pour les messages d'erreur