↑
CHAPITRE 10.1

Lire et écrire des fichiers

Manipuler des fichiers texte et binaires avec Reader/Writer et InputStream/OutputStream
Java fournit plusieurs classes pour lire et écrire des fichiers. Cette section présente les classes pour les fichiers texte (FileReader/FileWriter et leurs versions bufferisées) ainsi que les classes pour les fichiers binaires (FileInputStream/FileOutputStream et leurs versions bufferisées). Les Reader/Writer travaillent avec des caractères, tandis que les InputStream/OutputStream travaillent avec des octets.

10.1Lire et écrire des fichiers

10.1.1 – FileReader / FileWriter

FileReader et FileWriter sont des classes Java pour lire et écrire des fichiers texte caractère par caractère. Elles sont simples à utiliser mais moins performantes que les versions bufferisées pour de gros fichiers.

✍️ Écrire avec FileWriter

Exemple : Écriture dans un fichier

import java.io.FileWriter;
import java.io.IOException;

FileWriter writer = null;
try {
    writer = new FileWriter("fichier.txt");
    writer.write("Hello World");
    writer.write("\n");  // Nouvelle ligne
    writer.write("Deuxième ligne");
} catch (IOException e) {
    System.out.println("Erreur d'écriture : " + e.getMessage());
} finally {
    if (writer != null) {
        try {
            writer.close();  // Important : fermer le fichier
        } catch (IOException e) {
            System.out.println("Erreur de fermeture : " + e.getMessage());
        }
    }
}

đź“– Lire avec FileReader

Exemple : Lecture d'un fichier

import java.io.FileReader;
import java.io.IOException;

FileReader reader = null;
try {
    reader = new FileReader("fichier.txt");
    int caractere;
    while ((caractere = reader.read()) != -1) {
        System.out.print((char) caractere);  // Convertit int en char
    }
} catch (IOException e) {
    System.out.println("Erreur de lecture : " + e.getMessage());
} finally {
    if (reader != null) {
        try {
            reader.close();
        } catch (IOException e) {
            System.out.println("Erreur de fermeture : " + e.getMessage());
        }
    }
}

🆕 try-with-resources (recommandé)

Utilisez try-with-resources pour une gestion automatique de la fermeture.

Exemple : try-with-resources

// Écriture
try (FileWriter writer = new FileWriter("fichier.txt")) {
    writer.write("Hello World");
} catch (IOException e) {
    System.out.println("Erreur : " + e.getMessage());
}  // Fermeture automatique

// Lecture
try (FileReader reader = new FileReader("fichier.txt")) {
    int caractere;
    while ((caractere = reader.read()) != -1) {
        System.out.print((char) caractere);
    }
} catch (IOException e) {
    System.out.println("Erreur : " + e.getMessage());
}  // Fermeture automatique

10.1.2 – BufferedReader / BufferedWriter

BufferedReader et BufferedWriter sont des versions bufferisées qui améliorent les performances en lisant/écrivant par blocs plutôt que caractère par caractère. Ils sont particulièrement utiles pour lire/écrire ligne par ligne.

✍️ Écrire avec BufferedWriter

Exemple : Écriture bufferisée

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

try (BufferedWriter writer = new BufferedWriter(new FileWriter("fichier.txt"))) {
    writer.write("Ligne 1");
    writer.newLine();  // Méthode spécifique pour nouvelle ligne
    writer.write("Ligne 2");
    writer.newLine();
    writer.write("Ligne 3");
} catch (IOException e) {
    System.out.println("Erreur : " + e.getMessage());
}

đź“– Lire avec BufferedReader

BufferedReader permet de lire ligne par ligne avec la méthode readLine().

Exemple : Lecture bufferisée ligne par ligne

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

try (BufferedReader reader = new BufferedReader(new FileReader("fichier.txt"))) {
    String ligne;
    while ((ligne = reader.readLine()) != null) {
        System.out.println(ligne);  // Affiche chaque ligne
    }
} catch (IOException e) {
    System.out.println("Erreur : " + e.getMessage());
}

📊 Comparaison : FileReader vs BufferedReader

Caractéristique FileReader/FileWriter BufferedReader/BufferedWriter
Performance Plus lent (caractère par caractère) Plus rapide (par blocs)
Lecture ligne Non (caractère par caractère) Oui (readLine())
Cas d'usage Petits fichiers, caractère par caractère Gros fichiers, ligne par ligne

💡 Points clés à retenir

  • FileReader/FileWriter : Simple, caractère par caractère
  • BufferedReader/BufferedWriter : Plus performant, ligne par ligne
  • try-with-resources : Fermeture automatique (recommandĂ©)
  • IOException : Doit ĂŞtre gĂ©rĂ©e (exception vĂ©rifiĂ©e)
  • Fermeture : Toujours fermer les fichiers pour libĂ©rer les ressources

10.1.3 – FileInputStream / FileOutputStream

FileInputStream et FileOutputStream sont des classes Java pour lire et écrire des fichiers binaires (images, vidéos, fichiers exécutables, etc.). Contrairement aux Reader/Writer qui travaillent avec des caractères, les InputStream/OutputStream travaillent avec des octets (bytes).

Différence fondamentale :
  • Reader/Writer : Pour les fichiers texte (caractères Unicode)
  • InputStream/OutputStream : Pour les fichiers binaires (octets)

✍️ Écrire avec FileOutputStream

FileOutputStream permet d'écrire des données binaires dans un fichier octet par octet.

Exemple : Écriture de données binaires

import java.io.FileOutputStream;
import java.io.IOException;

// Écriture avec try-with-resources (recommandé)
try (FileOutputStream fos = new FileOutputStream("donnees.bin")) {
    byte[] donnees = {65, 66, 67, 68, 69};  // Octets à écrire
    fos.write(donnees);  // Écrit tout le tableau
    // ou
    fos.write(65);  // Écrit un seul octet
    fos.write(66);
} catch (IOException e) {
    System.out.println("Erreur d'écriture : " + e.getMessage());
}  // Fermeture automatique

đź“– Lire avec FileInputStream

FileInputStream permet de lire des données binaires depuis un fichier octet par octet.

Exemple : Lecture de données binaires

import java.io.FileInputStream;
import java.io.IOException;

try (FileInputStream fis = new FileInputStream("donnees.bin")) {
    int octet;
    while ((octet = fis.read()) != -1) {
        System.out.print(octet + " ");  // Affiche chaque octet
    }
} catch (IOException e) {
    System.out.println("Erreur de lecture : " + e.getMessage());
}  // Fermeture automatique

📦 Lecture par blocs

Pour de meilleures performances, on peut lire plusieurs octets Ă  la fois dans un tableau :

import java.io.FileInputStream;
import java.io.IOException;

try (FileInputStream fis = new FileInputStream("donnees.bin")) {
    byte[] buffer = new byte[1024];  // Buffer de 1024 octets
    int nombreOctetsLus;
    
    while ((nombreOctetsLus = fis.read(buffer)) != -1) {
        // Traiter les octets lus
        for (int i = 0; i < nombreOctetsLus; i++) {
            System.out.print(buffer[i] + " ");
        }
    }
} catch (IOException e) {
    System.out.println("Erreur : " + e.getMessage());
}
Explication :
  • read(buffer) lit jusqu'Ă  buffer.length octets dans le tableau
  • Retourne le nombre d'octets rĂ©ellement lus (peut ĂŞtre infĂ©rieur Ă  la taille du buffer)
  • Retourne -1 quand la fin du fichier est atteinte
  • Plus efficace que de lire octet par octet

10.1.4 – BufferedInputStream / BufferedOutputStream

BufferedInputStream et BufferedOutputStream sont des versions bufferisées qui améliorent considérablement les performances en lisant/écrivant par blocs plutôt que octet par octet. Ils sont recommandés pour tous les fichiers, surtout les gros fichiers binaires.

✍️ Écrire avec BufferedOutputStream

Exemple : Écriture bufferisée

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

try (BufferedOutputStream bos = new BufferedOutputStream(
        new FileOutputStream("donnees.bin"))) {
    byte[] donnees = {65, 66, 67, 68, 69, 70, 71, 72};
    bos.write(donnees);
    bos.flush();  // Force l'écriture du buffer (optionnel, fait automatiquement à la fermeture)
} catch (IOException e) {
    System.out.println("Erreur : " + e.getMessage());
}

đź“– Lire avec BufferedInputStream

Exemple : Lecture bufferisée

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;

try (BufferedInputStream bis = new BufferedInputStream(
        new FileInputStream("donnees.bin"))) {
    byte[] buffer = new byte[1024];
    int nombreOctetsLus;
    
    while ((nombreOctetsLus = bis.read(buffer)) != -1) {
        // Traiter les données lues
        for (int i = 0; i < nombreOctetsLus; i++) {
            System.out.print(buffer[i] + " ");
        }
    }
} catch (IOException e) {
    System.out.println("Erreur : " + e.getMessage());
}

📊 Comparaison : FileInputStream vs BufferedInputStream

Caractéristique FileInputStream/FileOutputStream BufferedInputStream/BufferedOutputStream
Performance Plus lent (octet par octet) Plus rapide (par blocs avec buffer)
Buffer Non Oui (par défaut 8192 octets)
Cas d'usage Petits fichiers, contrĂ´le fin Gros fichiers, meilleures performances
Recommandation Rarement utilisé directement Recommandé pour tous les fichiers

🎯 Exemple complet : Copie de fichier binaire

Voici un exemple complet qui copie un fichier binaire en utilisant les versions bufferisées :

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopieFichier {
    public static void copierFichier(String source, String destination) {
        try (
            BufferedInputStream bis = new BufferedInputStream(
                new FileInputStream(source));
            BufferedOutputStream bos = new BufferedOutputStream(
                new FileOutputStream(destination))
        ) {
            byte[] buffer = new byte[8192];  // Buffer de 8 Ko
            int nombreOctetsLus;
            
            while ((nombreOctetsLus = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, nombreOctetsLus);  // Écrit seulement les octets lus
            }
            
            System.out.println("Fichier copié avec succès");
        } catch (IOException e) {
            System.out.println("Erreur lors de la copie : " + e.getMessage());
        }
    }
    
    public static void main(String[] args) {
        copierFichier("image.jpg", "image_copie.jpg");
    }
}
Points importants de cet exemple :
  • Utilise BufferedInputStream et BufferedOutputStream pour de meilleures performances
  • Lit par blocs de 8192 octets (8 Ko) au lieu d'octet par octet
  • Écrit seulement les octets rĂ©ellement lus (important pour la dernière lecture)
  • Fermeture automatique avec try-with-resources
  • Fonctionne pour tous types de fichiers binaires (images, vidĂ©os, exĂ©cutables, etc.)

📋 Résumé : Reader/Writer vs InputStream/OutputStream

Aspect Reader/Writer InputStream/OutputStream
Type de données Caractères (char, String) Octets (byte)
Type de fichier Fichiers texte Fichiers binaires
Exemples .txt, .java, .xml, .json .jpg, .png, .mp4, .exe, .zip
Encodage Gère l'encodage (UTF-8, etc.) Pas d'encodage (données brutes)
Classes de base FileReader, FileWriter FileInputStream, FileOutputStream
Versions bufferisées BufferedReader, BufferedWriter BufferedInputStream, BufferedOutputStream

💡 Points clés à retenir

  • FileInputStream/FileOutputStream : Pour fichiers binaires, octet par octet
  • BufferedInputStream/BufferedOutputStream : Versions bufferisĂ©es, beaucoup plus performantes
  • Reader/Writer : Pour fichiers texte (caractères)
  • InputStream/OutputStream : Pour fichiers binaires (octets)
  • try-with-resources : Toujours utiliser pour la fermeture automatique
  • Lecture par blocs : Plus efficace que octet par octet
  • IOException : Doit toujours ĂŞtre gĂ©rĂ©e
Conseil pratique : Pour les fichiers binaires, utilisez toujours les versions bufferisées (BufferedInputStream/BufferedOutputStream) plutôt que les versions directes. La différence de performance est significative, surtout pour les gros fichiers. Pour les fichiers texte, préférez BufferedReader/BufferedWriter pour la lecture ligne par ligne.