Programmation Java

Classe SDA 7 2025-2026

Module 8

Fichiers et Entrées/Sorties

Manipuler des Fichiers et Gérer les Flux de Données

1. Le Concept Fondamental : Les Flux (Streams)

Avant de manipuler des fichiers, il faut comprendre comment Java "voit" les données. Java utilise le concept de flux (en anglais, stream).

Analogie : Une Rivière de Données

Flux d'Entrée : C'est une rivière qui coule depuis une source (un fichier, le clavier) vers votre programme. Vous l'utilisez pour lire des données.

Flux de Sortie : C'est une rivière qui coule depuis votre programme vers une destination (un fichier, la console). Vous l'utilisez pour écrire des données.

Les Deux Familles de Flux

→ Flux de Caractères (Reader/Writer)

Spécialisés pour lire et écrire du texte. Ils gèrent correctement l'encodage des caractères (comme UTF-8).

→ Flux d'Octets (InputStream/OutputStream)

Pour tout le reste (images, audio, fichiers binaires...).

Dans ce module, nous nous concentrerons sur les flux de caractères pour manipuler des fichiers texte.

2. La Manière Moderne et Simple (java.nio.file)

Depuis Java 7, une nouvelle API (NIO - New I/O) a été introduite pour simplifier la manipulation de fichiers. Pour des opérations simples, elle est beaucoup plus facile à utiliser pour un débutant.

→ Path

Un objet qui représente le chemin d'un fichier ou d'un dossier de manière indépendante du système d'exploitation.

→ Files

Une classe utilitaire remplie de méthodes statiques pour effectuer des opérations sur les fichiers.

Exemple 1 : Lire et Écrire un Fichier en Une Seule Ligne

Cette approche est parfaite pour les fichiers de petite taille que l'on peut charger entièrement en mémoire.

import java.nio.file.Path; import java.nio.file.Files; import java.io.IOException; public class NioFileExample { public static void main(String[] args) { Path filePath = Path.of("monFichierNio.txt"); try { // Écrire tout le contenu dans un fichier System.out.println("Écriture dans le fichier..."); Files.writeString(filePath, "Ceci est la manière moderne d'écrire.\nSimple et efficace !"); System.out.println("Écriture réussie."); // Lire tout le contenu d'un fichier en une seule fois System.out.println("\nLecture du fichier..."); String content = Files.readString(filePath); System.out.println("Contenu lu :\n" + content); } catch (IOException e) { System.out.println("Erreur : " + e.getMessage()); } } }
Quand Utiliser Cette Approche

Utilisez cette méthode pour :

  • Les fichiers petits et moyens
  • Quand vous devez charger ou écrire tout le contenu d'un coup
  • Pour une code simple et lisible

Pour aller plus loin :

Source: EvoluNoob

3. La Manière Traditionnelle et Contrôlée (java.io)

Pour des fichiers très volumineux ou lorsque vous avez besoin de traiter les données ligne par ligne sans tout charger en mémoire, l'approche traditionnelle avec les Reader et Writer est plus appropriée.

Le Principe des "Décorateurs"

L'API java.io utilise un modèle de "poupées russes" ou de "décorateurs".

Exemple 2 : Écriture Ligne par Ligne avec BufferedWriter

import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; public class FileWriteExample { public static void main(String[] args) { // Le "try-with-resources" garantit que le 'writer' sera fermé automatiquement try (BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"))) { writer.write("Bienvenue dans le monde des fichiers en Java!"); writer.newLine(); // Ajoute un saut de ligne writer.write("Ce texte est écrit ligne par ligne."); System.out.println("Écriture réussie."); } catch (IOException e) { System.out.println("Erreur : " + e.getMessage()); } } }
Le Try-With-Resources : Une Bonne Pratique Essentielle

La syntaxe try (...) garantit que le writer sera fermé automatiquement à la fin du bloc, même en cas d'erreur. C'est beaucoup mieux que de fermer manuellement avec finally !

Exemple 3 : Lecture Ligne par Ligne avec BufferedReader

import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; public class FileReadExample { public static void main(String[] args) { try (BufferedReader reader = new BufferedReader(new FileReader("output.txt"))) { String line; System.out.println("Lecture du contenu du fichier :"); // La boucle continue tant que readLine() ne renvoie pas 'null' while ((line = reader.readLine()) != null) { System.out.println(line); } } catch (IOException e) { System.out.println("Erreur : " + e.getMessage()); } } }

Exemple 4 : Ajouter du Contenu à un Fichier (Append)

Pour ajouter du texte à la fin d'un fichier sans l'écraser, on passe un second argument true au constructeur de FileWriter.

import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; public class FileAppendExample { public static void main(String[] args) { // 'true' active le mode ajout try (BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt", true))) { writer.newLine(); writer.write("Cette ligne est ajoutée à la fin."); System.out.println("Ajout réussi."); } catch (IOException e) { System.out.println("Erreur : " + e.getMessage()); } } }

4. Gestion des Exceptions IOException

Toutes les opérations sur les fichiers sont risquées : le fichier peut ne pas exister, le disque peut être plein, vous pouvez ne pas avoir les permissions... Pour cette raison, la plupart des méthodes déclarent qu'elles peuvent lancer une IOException. Java vous oblige à gérer cette "exception vérifiée" avec un bloc try-catch.

import java.io.FileReader; import java.io.IOException; public class IOExceptionExample { public static void main(String[] args) { try { // Tentative de lire un fichier qui n'existe probablement pas FileReader reader = new FileReader("fichier_inexistant.txt"); reader.close(); } catch (IOException e) { // On attrape l'erreur et on affiche un message clair System.out.println("Impossible de trouver le fichier!"); System.out.println("Détails : " + e.getMessage()); } } }
Important : Ne pas gérer une IOException causera une erreur de compilation. Java ne vous laisse pas ignorer les risques liés aux fichiers !

5. Comparaison des Deux Approches

Approche Avantages Inconvénients Quand l'utiliser
NIO (java.nio.file) Simple, modernes, lisible Charge tout en mémoire Fichiers petits/moyens
Traditionnelle (java.io) Contrôle fin, efficace pour gros fichiers Plus verbose Gros fichiers, streaming

Résumé : Ce que Vous Avez Appris

Les Points Clés du Module 8
  • Flux (Streams) - Comment Java gère les données qui entrent et sortent
  • API NIO moderne - La manière simple et moderne de lire/écrire des fichiers
  • API I/O traditionnelle - La manière contrôlée pour les fichiers volumineux
  • Try-with-resources - Garantir la fermeture des ressources automatiquement
  • IOException - Comment gérer les erreurs liées aux fichiers

Exercices Pratiques : Interagir avec des Fichiers

Mettez en pratique la lecture et l'écriture de fichiers, des compétences essentielles pour rendre vos applications persistantes.

Exercice 1 : Écrire et Lire une Liste de Courses (NIO)

Écrivez un programme qui crée une liste de courses sous forme de chaîne de caractères (avec des sauts de ligne \n) et l'écrit dans un fichier nommé `courses.txt`. Ensuite, le programme doit lire le contenu de ce même fichier et l'afficher dans la console.

Indice : Utilisez les méthodes statiques Files.writeString() et Files.readString() de la classe Files pour une solution simple et moderne.

Voir la solution
import java.nio.file.Path; import java.nio.file.Files; import java.io.IOException; public class ListeCourses { public static void main(String[] args) { Path cheminFichier = Path.of("courses.txt"); String contenuAEcrire = "Liste de courses :\n- Lait\n- Oeufs\n- Pain"; try { // Écriture dans le fichier Files.writeString(cheminFichier, contenuAEcrire); System.out.println("Le fichier 'courses.txt' a été créé avec succès."); // Lecture du fichier String contenuLu = Files.readString(cheminFichier); System.out.println("\n--- Contenu du fichier ---"); System.out.println(contenuLu); } catch (IOException e) { System.err.println("Une erreur est survenue : " + e.getMessage()); } } }

Exercice 2 : Numéroteur de Lignes (I/O)

Créez un fichier texte nommé `poeme.txt` avec quelques lignes de votre choix. Écrivez un programme Java qui lit ce fichier ligne par ligne et affiche chaque ligne dans la console, précédée de son numéro de ligne.

Indice : Utilisez un BufferedReader enveloppé dans un FileReader. Une boucle while avec la condition (ligne = reader.readLine()) != null est parfaite pour cela. N'oubliez pas une variable compteur !

Voir la solution
import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; public class LineNumberer { public static void main(String[] args) { // Assurez-vous d'avoir créé un fichier 'poeme.txt' à côté de votre .java String nomFichier = "poeme.txt"; try (BufferedReader reader = new BufferedReader(new FileReader(nomFichier))) { String ligne; int numeroLigne = 1; System.out.println("--- Contenu de " + nomFichier + " ---"); while ((ligne = reader.readLine()) != null) { System.out.println(numeroLigne + ": " + ligne); numeroLigne++; } } catch (IOException e) { System.err.println("Erreur de lecture du fichier : " + e.getMessage()); } } }

Exercice 3 : Journal d'Événements (Append)

Créez un programme qui simule un journal d'événements (log). Écrivez une méthode log(String message) qui prend un message en paramètre et l'ajoute à la fin d'un fichier nommé `journal.log`. Chaque message doit être sur une nouvelle ligne.

Appelez cette méthode plusieurs fois dans votre main pour vérifier que les messages s'ajoutent bien les uns à la suite des autres sans écraser le contenu précédent.

Indice : Pour ajouter du contenu, vous devez utiliser le constructeur new FileWriter("journal.log", true). Le second paramètre true active le mode "append".

Voir la solution
import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; public class Logger { public static void log(String message) { // Le 'true' est la clé pour le mode ajout (append) try (BufferedWriter writer = new BufferedWriter(new FileWriter("journal.log", true))) { writer.write(message); writer.newLine(); // Pour que chaque log soit sur sa propre ligne } catch (IOException e) { System.err.println("Impossible d'écrire dans le journal : " + e.getMessage()); } } public static void main(String[] args) { System.out.println("Enregistrement de plusieurs événements..."); log("INFO: Le programme a démarré."); log("WARN: L'utilisateur a tenté une action invalide."); log("INFO: Le programme s'est terminé normalement."); System.out.println("Vérifiez le contenu du fichier 'journal.log'."); } }