Comment lire un fichier ligne par ligne en Java
Lisez un fichier Java ligne par ligne avec BufferedReader, Files.lines, Files.readAllLines et Scanner.
Lire un fichier texte une ligne à la fois est l'une des tâches de fichier les plus courantes en Java. Le JDK vous offre plusieurs façons de le faire ; le bon choix dépend de la taille du fichier et de si vous voulez une boucle classique ou un pipeline de flux. Ce chapitre présente les quatre approches idiomatiques et quand les utiliser.
BufferedReader : le cheval de bataille du flux
BufferedReader.readLine() lit une seule ligne par appel et renvoie null en fin de fichier, ce qui s'associe naturellement à une boucle while. Enveloppez-le dans try-with-resources pour que le lecteur sous-jacent se ferme automatiquement :
Path file = Path.of("notes.txt");
try (BufferedReader br = Files.newBufferedReader(file, StandardCharsets.UTF_8)) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}Cela diffuse le fichier : une seule ligne est conservée en mémoire à la fois, ce qui permet de gérer un journal de plusieurs gigaoctets sans problème. Files.newBufferedReader utilise UTF-8 par défaut, mais passer le jeu de caractères explicitement documente l'intention et évite un décodage dépendant de la plateforme. Notez que readLine() supprime le terminateur de ligne (\n, \r ou \r\n), donc vous ne le verrez jamais dans la chaîne renvoyée.
La forme try (...) ci-dessus est try-with-resources : elle garantit que le lecteur est fermé même si la boucle lève une exception. Voir les flux mis en mémoire tampon pour comprendre pourquoi encapsuler un lecteur brut dans un BufferedReader est important pour les performances.
Files.lines : le même travail sous forme de Stream
Lorsque vous voulez un pipeline fonctionnel — filter, map, count — Files.lines vous donne un Stream<String> paresseux sur les lignes du fichier :
try (Stream<String> lines = Files.lines(Path.of("notes.txt"), StandardCharsets.UTF_8)) {
lines.filter(s -> !s.isBlank())
.map(String::trim)
.forEach(System.out::println);
}Comme BufferedReader, il lit paresseusement et ne charge jamais le fichier entier. L'inconvénient est que le flux conserve un descripteur de fichier ouvert, donc il doit être fermé — utilisez-le toujours dans un try-with-resources, jamais comme expression nue. Oublier cela entraîne des fuites de descripteurs.
Files.readAllLines : les petits fichiers, tout d'un coup
Si le fichier est petit et que vous voulez toutes les lignes dans une List<String> d'emblée, Files.readAllLines est l'option la plus directe :
List<String> all = Files.readAllLines(Path.of("notes.txt"), StandardCharsets.UTF_8);
for (String line : all) {
System.out.println(line);
}Il est avide : le fichier entier est décodé en mémoire avant que vous touchiez la première ligne. C'est pratique pour les fichiers de configuration et les fixtures, mais peu adapté aux fichiers volumineux — préférez les approches par flux dans ce cas. Scanner avec nextLine() et hasNextLine() est une quatrième option, utile lorsque vous devez aussi analyser des tokens, mais il est plus lent et facile à mal utiliser, donc les trois approches ci-dessus couvrent la plupart des cas. Pour un aperçu plus large des E/S de fichiers — ouverture, lecture de fichiers entiers et l'API NIO Files — voir lire des fichiers en Java.
| Approche | Mémoire | Retourne | Idéal pour |
|---|---|---|---|
BufferedReader.readLine() | Une ligne | Boucle classique | Grands fichiers, contrôle manuel |
Files.lines() | Une ligne (paresseux) | Stream<String> | Pipelines sur grands fichiers |
Files.readAllLines() | Fichier entier | List<String> | Petits fichiers, accès aléatoire |
Scanner.nextLine() | Une ligne | Boucle classique | Analyse mixte ligne + token |
Exemple complet : les trois méthodes côte à côte
Ce programme crée un petit fichier temporaire (pour être autonome), puis le lit de trois façons — une boucle BufferedReader, un flux Files.lines, et un Files.readAllLines avide :
Ce qu'il faut retenir de l'exécution :
- La boucle
BufferedReadernumérote quatre lignes, et la ligne3: []montre qu'une ligne vide dans le fichier est renvoyée comme une chaîne vide, pas ignorée —readLine()rapporte chaque ligne, y compris les lignes vides. readLine()a affiché chaque ligne sans\nfinal, confirmant qu'il supprime le terminateur de ligne ; les seuls crochets autour du texte sont les[et]littéraux ajoutés par le code.Files.linesa compténon-blank lines: 3parce que lefilter(s -> !s.isBlank())a supprimé la ligne vide — le pipeline de flux opère paresseusement sur les mêmes quatre lignes que la boucle a vues.Files.readAllLinesa rapportétotal lines: 4etfirst line : alpha, prouvant qu'il a chargé le fichier entier de manière avide dans uneList<String>que vous pouvez indexer avecget(0).- Chaque lecteur était à l'intérieur d'un try-with-resources (ou a renvoyé une
Listgérée), donc le descripteur de fichier et le fichier temporaire ont été libérés proprement avant l'affichage dedone— aucune fuite de descripteurs.