Adloun

Fichiers et flux

Cours · programmation Java (école d'ingénieur), chapitre 14 · école d'ingénieur, informatique · le début du chapitre, la suite sur Adloun

Jusqu'ici, nos programmes oubliaient tout en s'arrêtant : les données venaient du clavier ou étaient écrites dans le code, les résultats partaient à l'écran. Un vrai logiciel, lui, garde ses données : un tableur enregistre ses feuilles, un jeu sauvegarde la partie, un serveur écrit ses journaux. Ce chapitre apprend à lire et à écrire des fichiers en Java : des fichiers texte d'abord (le cas le plus fréquent), puis des fichiers binaires.

À faire sur votre ordinateur

Les programmes de ce chapitre lisent et écrivent sur le disque. L'Éditeur Java de la plateforme, qui tourne dans le navigateur, n'a pas accès au système de fichiers : il faut un JDK installé sur votre ordinateur, et exécuter les programmes dans un terminal (ou dans un environnement de développement). Les fichiers sont lus et créés dans le dossier courant, celui depuis lequel on lance java.

Objectifs du chapitre

  • Désigner un fichier par un chemin (Path), relatif ou absolu.
  • Lire et écrire un fichier texte en une instruction avec la classe Files.
  • Lire un gros fichier ligne par ligne avec un BufferedReader, écrire avec un PrintWriter.
  • Comprendre la différence entre caractères et octets, et le rôle de l'encodage (UTF-8).
  • Fermer systématiquement ses fichiers avec try-avec-ressources et traiter les IOException.
  • Écrire et relire des données binaires.

14.1 Fichiers et chemins

14.1.1 Qu'est-ce qu'un fichier ?

Définition 14.1Fichier, dossier, chemin

Un fichier est une suite d'octets enregistrée sur un support de stockage (disque, clé USB…) et désignée par un nom. Les fichiers sont rangés dans des dossiers (ou répertoires), eux-mêmes rangés dans des dossiers : ils forment une arborescence. Un chemin désigne un fichier ou un dossier dans cette arborescence, par la suite des noms des dossiers à traverser.

Un chemin peut être :

Deux noms sont réservés : . désigne le dossier lui-même et .. le dossier parent.

Attention

Un programme qui ouvre notes.csv cherche ce fichier dans le dossier courant, pas dans le dossier où se trouve le fichier .java ou .class. C'est la première cause de l'erreur « fichier introuvable » chez les débutants : vérifiez d'où vous lancez le programme.

14.1.2 La classe Path

Depuis Java 7, un chemin est représenté par un objet de type java.nio.file.Path, que l'on fabrique avec Path.of(...) (ou, dans du code plus ancien, Paths.get(...), qui fait la même chose). On lui donne les noms successifs, et Java insère lui-même le bon séparateur (/ ou \) selon le système.


import java.nio.file.Path;

/** Chapitre 14 — manipuler des chemins (sans toucher au disque). */
public class Chemins {
    public static void main(String[] args) {
        Path p = Path.of("donnees", "notes.csv");      // chemin relatif
        System.out.println("Chemin          : " + p);
        System.out.println("Nom du fichier  : " + p.getFileName());
        System.out.println("Dossier parent  : " + p.getParent());
        System.out.println("Absolu ?        : " + p.isAbsolute());
        System.out.println("Nombre de noms  : " + p.getNameCount());

        Path q = Path.of("/home/eleve/projet");          // chemin absolu (Unix)
        System.out.println("Absolu ?        : " + q.isAbsolute());
        System.out.println("Résolution      : " + q.resolve(p));
        System.out.println("Normalisation   : " + Path.of("a/b/../c/./d.txt").normalize());
        System.out.println("Relatif         : " + q.relativize(Path.of("/home/eleve/cours/java")));

        // Un chemin relatif se lit à partir du dossier courant du programme :
        Path absolu = p.toAbsolutePath();
        System.out.println("Se termine par p : " + absolu.endsWith(p));
    }
}

Chemin          : donnees/notes.csv
Nom du fichier  : notes.csv
Dossier parent  : donnees
Absolu ?        : false
Nombre de noms  : 2
Absolu ?        : true
Résolution      : /home/eleve/projet/donnees/notes.csv
Normalisation   : a/c/d.txt
Relatif         : ../cours/java
Se termine par p : true

Un Path n'est qu'un nom : le créer ne crée aucun fichier et ne vérifie pas qu'il existe. resolve colle un chemin relatif au bout d'un autre, normalize élimine les . et les .., relativize calcule le chemin pour aller de l'un à l'autre, et toAbsolutePath complète un chemin relatif par le dossier courant.

14.2 Lire et écrire en une instruction : la classe Files

La classe java.nio.file.Files rassemble des méthodes static pour agir sur les fichiers. Les plus utiles :

MéthodeEffet
Files.exists(p)le fichier ou le dossier existe-t-il ?
Files.size(p)taille du fichier, en octets
Files.readString(p)tout le contenu, dans une String
Files.readAllLines(p)toutes les lignes, dans une List
Files.writeString(p, s)écrit la chaîne s
Files.write(p, lignes)écrit une liste de lignes
Files.lines(p)un flux (Stream) des lignes
Files.delete(p)supprime le fichier
Files.createDirectories(p)crée un dossier (et ses parents)

Par défaut, ces méthodes lisent et écrivent en UTF-8 (section 14.3), et les méthodes d'écriture écrasent le fichier s'il existe déjà. Pour écrire à la suite du contenu existant, on ajoute en dernier argument l'option StandardOpenOption.APPEND.


import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

/** Chapitre 14 — écrire puis relire un fichier texte avec la classe Files. */
public class LireEcrire {
    public static void main(String[] args) throws IOException {
        Path f = Path.of("courses.txt");

        // 1) Écrire une liste de lignes (le fichier est créé ou écrasé)
        List<String> lignes = List.of("pain", "lait", "œufs", "café");
        Files.write(f, lignes);
        System.out.println("Existe : " + Files.exists(f) + ", taille : " + Files.size(f) + " octets");

        // 2) Ajouter une ligne à la fin
        Files.writeString(f, "pâtes\n", java.nio.file.StandardOpenOption.APPEND);

        // 3) Relire tout le fichier, ligne par ligne
        List<String> relues = Files.readAllLines(f);
        for (int i = 0; i < relues.size(); i++)
            System.out.println((i + 1) + " : " + relues.get(i));

        // 4) Relire tout le fichier d'un bloc
        String tout = Files.readString(f);
        System.out.println("Caractères : " + tout.length());
    }
}

Existe : true, taille : 22 octets
1 : pain
2 : lait
3 : œufs
4 : café
Caractères : 26

Remarquez deux choses. D'abord Files.write termine chaque ligne par un saut de ligne : les quatre lignes occupent octets, et non . Ensuite le fichier final contient caractères mais octets : « œ », « é » et « â » occupent deux octets chacun en UTF-8. Nous y reviendrons.

La suite du cours est sur Adloun

Le chapitre en entier, formules et figures comprises, avec le tuteur, les fiches, les QCM et les exercices.

Lire la suite du cours

En accès libre, sans inscription.

Exercices corrigés de ce chapitre

Lire la suite du cours →