1. Lecture du fichier ligne par ligne : BufferedReader et compagnie
Nous avons déjà abordé la lecture octet par octet : c’est pratique pour les formats binaires, mais pour le texte cette approche n’est pas idéale. Un fichier texte est composé de caractères qui dépendent de l’encodage. Java propose donc des « surcouches » — FileReader, BufferedReader et d’autres classes — qui transforment un flux d’octets en flux de caractères et de lignes.
Imaginez un fichier texte — qu’il s’agisse du journal d’exécution d’un programme, d’une liste d’utilisateurs ou même du roman fleuve « Guerre et Paix ». Parfois, il faut lire rapidement tout le fichier d’un coup, parfois le parcourir ligne par ligne, et parfois extraire une ligne précise.
En Java, plusieurs méthodes existent, et le choix dépend de la taille du fichier et de la tâche. Si vous devez traiter le fichier ligne par ligne (par exemple compter le nombre de lignes ou trouver une entrée), utilisez la lecture ligne par ligne. Et si le fichier est petit, vous pouvez le charger entièrement en mémoire et travailler avec comme avec une liste de lignes.
Pourquoi la lecture ligne par ligne est-elle une bonne idée ?
Pour les gros fichiers, la lecture ligne par ligne évite les problèmes de mémoire. Charger en mémoire un journal de plusieurs gigaoctets est une mauvaise idée : vous risquez de tomber sur une OutOfMemoryError. En revanche, lire le fichier ligne après ligne est peu coûteux, même s’il pèse des centaines de mégaoctets.
Comment faire en Java ?
La méthode la plus classique consiste à utiliser BufferedReader (ou ses proches) et la méthode readLine().
import java.io.*;
public class ReadLinesDemo {
public static void main(String[] args) {
String fileName = "example.txt";
try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
String line;
int lineNumber = 1;
while ((line = reader.readLine()) != null) {
System.out.printf("%3d: %s%n", lineNumber, line);
lineNumber++;
}
} catch (IOException e) {
System.out.println("Erreur lors de la lecture du fichier: " + e.getMessage());
}
}
}
Ici, nous ouvrons le fichier en lecture et, avec readLine(), nous lisons une ligne à la fois jusqu’à la fin (null). Ensuite, nous affichons chaque ligne avec son numéro.
En bref sur try-with-resources
Voyez-vous la construction try (...) { ... } ? C’est try-with-resources. Elle garantit que le fichier sera fermé, même si une erreur survient en cours de lecture. Vous n’avez pas à appeler close() manuellement : la fermeture se produira automatiquement, même avec catch/finally.
Pourquoi utiliser BufferedReader ?
BufferedReader ne lit pas caractère par caractère, mais par blocs (généralement de 8192 octets), ce qui accélère le travail avec les fichiers. De plus, il possède la méthode pratique readLine(), qui retourne la ligne jusqu’au caractère de fin de ligne.
Quelle taille de tampon choisir ?
En général, BufferedReader utilise un tampon de 8192 octets (8 Ko) — suffisant pour la plupart des cas. Si vous lisez des lignes très longues (par exemple 100_000 caractères), vous pouvez augmenter le tampon :
BufferedReader reader = new BufferedReader(new FileReader(fileName), 65536); // tampon de 64 Ko
Mais pour les tâches ordinaires, la taille par défaut convient parfaitement.
2. Lecture du fichier en entier : Files.readAllLines et Files.readString
Si le fichier est petit (par exemple jusqu’à 10–20 Mo), il est pratique de le charger en entier. Par exemple, si vous devez rapidement obtenir la liste de toutes les lignes, analyser le texte ou l’envoyer sur le réseau.
Approche moderne : Files.readAllLines
Depuis Java 7, la classe Files propose de nombreuses méthodes utiles.
import java.nio.file.*;
import java.io.IOException;
import java.util.List;
public class ReadAllLinesDemo {
public static void main(String[] args) {
Path path = Path.of("example.txt");
try {
List<String> lines = Files.readAllLines(path);
for (int i = 0; i < lines.size(); i++) {
System.out.printf("%3d: %s%n", i + 1, lines.get(i));
}
} catch (IOException e) {
System.out.println("Erreur lors de la lecture du fichier: " + e.getMessage());
}
}
}
Ici, la méthode Files.readAllLines(path) renvoie une liste de lignes (List<String>). Vous pouvez manipuler cette liste comme une collection ordinaire : rechercher, trier, filtrer.
Encore plus moderne : Files.readString (Java 11+)
Si vous devez obtenir tout le fichier dans une seule chaîne (par exemple pour rechercher une sous-chaîne ou l’envoyer en JSON), utilisez Files.readString :
import java.nio.file.*;
import java.io.IOException;
public class ReadStringDemo {
public static void main(String[] args) {
Path path = Path.of("example.txt");
try {
String content = Files.readString(path);
System.out.println("Contenu du fichier:");
System.out.println(content);
} catch (IOException e) {
System.out.println("Erreur lors de la lecture du fichier: " + e.getMessage());
}
}
}
Et l’encodage ?
Par défaut, les méthodes Files.readAllLines et Files.readString utilisent l’encodage standard de votre système. Si le fichier a été enregistré dans un autre encodage (par exemple Windows-1251), indiquez-le explicitement :
List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8);
String content = Files.readString(path, StandardCharsets.UTF_8);
3. Comparaison des approches : quand utiliser laquelle
| Approche | Quand l’utiliser | Avantages | Inconvénients |
|---|---|---|---|
|
Grands fichiers, traitement ligne par ligne | Économe en mémoire, flexible | Lecture uniquement ligne par ligne |
|
Petits et moyens fichiers | Renvoie directement une liste de lignes, simple | Pour les gros fichiers — OutOfMemory |
|
Petits fichiers, besoin de tout le texte | Texte complet en une seule chaîne | Pas de découpage en lignes |
Recommandation:
— Si le fichier est petit, utilisez Files.readAllLines ou Files.readString.
— Si le fichier est volumineux ou si vous ne connaissez pas sa taille, utilisez BufferedReader.readLine().
4. Tâches pratiques : exemples et analyse
Exemple 1. Comptage des lignes dans un gros fichier
Supposons que vous deviez connaître le nombre de lignes dans un fichier volumineux (par exemple, un journal de serveur).
import java.io.*;
public class LineCount {
public static void main(String[] args) {
String fileName = "biglog.txt";
int lineCount = 0;
try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
while (reader.readLine() != null) {
lineCount++;
}
System.out.println("Nombre total de lignes dans le fichier: " + lineCount);
} catch (IOException e) {
System.out.println("Erreur lors de la lecture du fichier: " + e.getMessage());
}
}
}
Exemple 2. Recherche de lignes par contenu
Recherchons toutes les lignes contenant le mot « erreur » (insensible à la casse) :
import java.io.*;
public class FindErrorLines {
public static void main(String[] args) {
String fileName = "biglog.txt";
String keyword = "erreur";
try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
String line;
int lineNumber = 1;
while ((line = reader.readLine()) != null) {
if (line.toLowerCase().contains(keyword)) {
System.out.printf("%3d: %s%n", lineNumber, line);
}
lineNumber++;
}
} catch (IOException e) {
System.out.println("Erreur lors de la lecture du fichier: " + e.getMessage());
}
}
}
Exemple 3. Chargement d’une configuration depuis un petit fichier
Fichier config.txt :
host=localhost
port=8080
mode=dev
Nous le lisons en entier et l’analysons en paires clé-valeur :
import java.nio.file.*;
import java.util.*;
public class ConfigLoader {
public static void main(String[] args) throws Exception {
Path path = Path.of("config.txt");
List<String> lines = Files.readAllLines(path);
Map<String, String> config = new HashMap<>();
for (String line : lines) {
if (line.trim().isEmpty() || line.startsWith("#")) continue; // on ignore les lignes vides et les commentaires
String[] parts = line.split("=", 2);
if (parts.length == 2) {
config.put(parts[0].trim(), parts[1].trim());
}
}
System.out.println("Configuration chargée: " + config);
}
}
5. Erreurs courantes lors de la lecture de fichiers texte
Erreur n°1: Tenter de lire un fichier binaire comme un fichier texte. Si vous ouvrez une image ou une archive avec BufferedReader ou Files.readAllLines, vous obtiendrez des caractères incohérents et vous risquez une OutOfMemoryError. Pour les fichiers binaires, utilisez InputStream !
Erreur n°2: Ne pas gérer les exceptions. Les fichiers peuvent être supprimés, déplacés, verrouillés. Enveloppez toujours la lecture dans un bloc try-catch et informez l’utilisateur en cas de problème.
Erreur n°3: Ignorer l’encodage. Si votre texte est en russe et que vous lisez le fichier sans spécifier l’encodage, vous pouvez obtenir « ????? ». Utilisez StandardCharsets.UTF_8 ou l’encodage nécessaire.
Erreur n°4: Oublier de fermer le flux. Si vous ne fermez pas le fichier, il peut rester verrouillé jusqu’à la fin du programme. Utilisez toujours try-with-resources.
Erreur n°5: Utiliser read() au lieu de readLine() pour les fichiers texte. La méthode read() lit caractère par caractère — c’est lent et peu pratique pour des lignes. Pour le texte, utilisez readLine() ou les méthodes de la classe Files.
GO TO FULL VERSION