W3docs

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.

ApprocheMémoireRetourneIdéal pour
BufferedReader.readLine()Une ligneBoucle classiqueGrands fichiers, contrôle manuel
Files.lines()Une ligne (paresseux)Stream<String>Pipelines sur grands fichiers
Files.readAllLines()Fichier entierList<String>Petits fichiers, accès aléatoire
Scanner.nextLine()Une ligneBoucle classiqueAnalyse 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 :

java— editable, runs on the server

Ce qu'il faut retenir de l'exécution :

  • La boucle BufferedReader numérote quatre lignes, et la ligne 3: [] 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 \n final, 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.lines a compté non-blank lines: 3 parce que le filter(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.readAllLines a rapporté total lines: 4 et first line : alpha, prouvant qu'il a chargé le fichier entier de manière avide dans une List<String> que vous pouvez indexer avec get(0).
  • Chaque lecteur était à l'intérieur d'un try-with-resources (ou a renvoyé une List gérée), donc le descripteur de fichier et le fichier temporaire ont été libérés proprement avant l'affichage de done — aucune fuite de descripteurs.

Pratique

Pratique
Pourquoi un flux retourné par Files.lines() doit-il être utilisé dans un bloc try-with-resources ?
Pourquoi un flux retourné par Files.lines() doit-il être utilisé dans un bloc try-with-resources ?
Was this page helpful?