Menu

Écrire et lire un fichier en C# : File, StreamWriter, StreamReader

Comment écrire dans un fichier et lire un fichier en C# : File.WriteAllText, ReadAllText, AppendAllText, WriteAllLines et ReadAllLines pour les fichiers entiers, StreamWriter et StreamReader pour les gros fichiers, les chemins avec Path.Combine, les dossiers, les encodages, et les exceptions que le code de fichiers doit gérer.

Cette page contient des éditeurs exécutables - modifiez, exécutez et voyez la sortie instantanément.

Le namespace System.IO contient tout ce qu'il faut pour travailler avec des fichiers. Pour la plupart des tâches, un seul appel sur la classe statique File suffit : il ouvre le fichier, le lit ou l'écrit, et le ferme. Pour les gros fichiers ou un contrôle fin, utilisez StreamReader et StreamWriter. Ajoutez using System.IO; à chaque exemple ci-dessous.

Écrire et lire un fichier entier

File.WriteAllText crée un fichier (ou écrase un fichier existant) avec le texte que vous lui donnez. File.ReadAllText renvoie tout le fichier en une seule chaîne. File.AppendAllText ajoute à la fin :

Sortie :

True
Buy coffee
Call the dentist
Renew passport
43 characters
Start over
False

Un chemin relatif comme "notes.txt" est résolu par rapport au répertoire courant du processus, qui n'est pas toujours le dossier où se trouve votre programme (un service, une tâche planifiée ou un lanceur de tests peut démarrer ailleurs). Pour les fichiers livrés avec votre application, construisez le chemin à partir de AppContext.BaseDirectory.

WriteAllText écrase sans demander. Si perdre l'ancien contenu est gênant, vérifiez d'abord File.Exists ou écrivez dans un fichier temporaire puis mettez-le en place avec File.Move.

Lignes : WriteAllLines, ReadAllLines et ReadLines

Les fichiers d'enregistrements, un par ligne, sont assez courants pour avoir leurs propres méthodes. WriteAllLines écrit chaque chaîne suivie d'un saut de ligne ; ReadAllLines renvoie un string[] :

Sortie :

4 lines, header: date,product,amount
Total: 45.60
2026-03-03,Stapler,7.00

La différence entre les deux lecteurs compte pour la taille. ReadAllLines lit tout le fichier en mémoire avant de revenir. ReadLines renvoie un IEnumerable<string> paresseux qui lit au fil de l'itération, donc un foreach sur un log de 5 Go n'utilise que quelques kilo-octets. Avec LINQ, ReadLines(...).Where(...).Take(10) arrête de lire une fois qu'il a dix correspondances.

Analyser du CSV avec Split(',') fonctionne pour des fichiers simples que vous avez produits vous-même. Le CSV du monde réel contient des champs entre guillemets qui renferment des virgules ; utilisez pour ceux-là une bibliothèque comme CsvHelper.

Remarquez l'InvariantCulture dans decimal.Parse : sans elle, analyser "4.50" sur une machine réglée en allemand ou en portugais lit le point comme un séparateur de milliers.

StreamWriter et StreamReader

Les méthodes de File ouvrent et ferment le fichier à chaque appel. Pour écrire de nombreux morceaux au fil du temps, ou lire un fichier trop gros pour la mémoire sans LINQ, ouvrez un flux une seule fois. Enveloppez-le toujours dans using pour qu'il soit fermé même si une exception est levée ; un writer non fermé peut ne jamais vider son tampon, et le fichier se retrouve vide ou tronqué.

Sortie :

2: WARN  disk 85% full
4: ERROR connection refused

ReadLine renvoie null à la fin du fichier, ce qui termine la boucle while. Un StreamWriter met sa sortie en tampon et l'écrit sur le disque quand le tampon est plein, quand vous appelez Flush() et quand il est libéré ; le bloc using garantit ce dernier cas.

Depuis C# 8, une déclaration using libère le flux à la fin du bloc englobant, sans les accolades supplémentaires :

using var writer = new StreamWriter(path);   // C# 8: disposed when the method returns
writer.WriteLine("INFO  server started");

Chemins et dossiers

Construisez les chemins avec Path.Combine plutôt que par concaténation de chaînes. Il insère le bon séparateur pour le système d'exploitation (\ sous Windows, / sous Linux et macOS) et ne le double pas. La classe Path décompose aussi les chemins, et Directory crée et liste les dossiers :

Sortie :

february.txt, january.txt, march.txt
march.txt
march
.txt
march.pdf
False

Un piège : si un argument ultérieur de Path.Combine est un chemin racine (il commence par / ou \, ou par une lettre de lecteur sous Windows), tout ce qui précède est abandonné, donc Path.Combine("reports", "/2026") donne /2026. Passez des parties relatives, ou utilisez Path.Join (.NET Core 3.0 et plus), qui n'abandonne jamais rien.

Directory.GetFiles renvoie les fichiers dans l'ordre fourni par le système de fichiers, qui diffère entre Windows et Linux, donc triez le résultat quand l'ordre compte. Directory.EnumerateFiles est la version paresseuse, dans le même rapport que ReadLines avec ReadAllLines. Passez SearchOption.AllDirectories pour inclure les sous-dossiers.

Gérer les erreurs

Les opérations sur les fichiers échouent pour des raisons extérieures à votre programme : le fichier manque, le dossier n'existe pas, un autre processus l'a ouvert, le disque est plein, les permissions sont incorrectes. Chaque cas a son propre type d'exception. FileNotFoundException et DirectoryNotFoundException dérivent de IOException, donc interceptez-les avant elle ; UnauthorizedAccessException n'en dérive pas, elle a donc besoin de son propre catch :

Sortie :

missing file, using defaults
missing folder, using defaults
theme=dark

Un File.Exists avant la lecture semble plus simple, mais il ne dispense pas du try : le fichier peut disparaître, ou être verrouillé par un autre programme, entre la vérification et la lecture. Utilisez Exists pour décider quoi faire, et catch pour survivre à ce qui se passe réellement.

Encodage

File.WriteAllText, WriteAllLines et StreamWriter écrivent par défaut en UTF-8 sans marque d'ordre des octets (BOM), et les lecteurs détectent UTF-8, UTF-16 et UTF-32 à partir d'une BOM si elle est présente. Passez un Encoding quand un fichier doit être dans un format précis :

Sortie :

plain.txt   16 bytes, reads back unchanged: True
bom.txt     19 bytes, reads back unchanged: True
utf16.txt   30 bytes, reads back unchanged: True

é et ã occupent deux octets chacun en UTF-8, c'est pourquoi 14 caractères demandent 16 octets, et les trois fichiers se relisent correctement parce que le lecteur reconnaît la BOM. Encoding.UTF8 ressemble à la valeur par défaut mais ajoute une BOM, que certains outils (anciens importateurs CSV, scripts shell) affichent comme des caractères parasites au début de la première ligne ; utilisez new UTF8Encoding(false) pour de l'UTF-8 explicite sans BOM. Lire un fichier dans le mauvais encodage ne lève pas d'exception : cela produit des caractères de remplacement, donc renseignez-vous sur l'encodage d'un fichier que vous n'avez pas créé.

E/S de fichiers asynchrones

Dans les applications web et le code d'interface, bloquer un thread sur des E/S disque le gaspille. .NET Core 2.0 et plus proposent des versions async des méthodes de File :

await File.WriteAllTextAsync("notes.txt", text);
string content = await File.ReadAllTextAsync("notes.txt");
string[] lines = await File.ReadAllLinesAsync("sales.csv");

StreamReader.ReadLineAsync et StreamWriter.WriteLineAsync fonctionnent de la même façon sur les flux.

Erreurs courantes

  • Ne pas libérer un flux. Sans using, le texte en tampon peut ne jamais atteindre le disque et le fichier reste verrouillé jusqu'au passage du ramasse-miettes.
  • Construire des chemins avec + "\\" +. Cela casse sous Linux et macOS. Utilisez Path.Combine.
  • Charger d'énormes fichiers avec ReadAllText ou ReadAllLines. Lisez-les en flux avec ReadLines ou un StreamReader.
  • Compter sur le répertoire courant. Il dépend de la façon dont le programme a été lancé. Utilisez des chemins absolus ou AppContext.BaseDirectory.
  • Analyser des nombres venant de fichiers avec la culture de la machine. Passez CultureInfo.InvariantCulture pour les fichiers de données.
  • S'attendre à ce que File.Exists empêche les exceptions. Le fichier peut changer entre la vérification et l'utilisation.

Questions fréquentes

Comment écrire du texte dans un fichier en C# ?

File.WriteAllText("notes.txt", text); crée le fichier, ou l'écrase s'il existe, écrit la chaîne en UTF-8 et le ferme. Utilisez File.WriteAllLines(path, lines) pour une collection de lignes et File.AppendAllText(path, text) pour ajouter à la fin au lieu de remplacer. Les trois se trouvent dans System.IO.

Comment lire un fichier texte en C# ?

string text = File.ReadAllText("notes.txt"); lit tout le fichier en une seule chaîne, et string[] lines = File.ReadAllLines(path); le découpe en lignes. Pour les gros fichiers, utilisez File.ReadLines(path) dans un foreach, qui lit une ligne à la fois au lieu de tout charger, ou un StreamReader.

Comment ajouter du texte à un fichier en C# ?

File.AppendAllText(path, text) ajoute du texte à la fin du fichier et crée le fichier s'il n'existe pas ; File.AppendAllLines(path, lines) fait de même pour des lignes. Avec un flux, ouvrez-le en mode ajout : new StreamWriter(path, append: true). Pensez à ajouter vous-même Environment.NewLine ou \n quand vous ajoutez du texte.

Comment lire un fichier ligne par ligne en C# ?

foreach (string line in File.ReadLines(path)) { ... } lit le fichier une ligne à la fois, donc la mémoire utilisée reste stable même pour des logs de plusieurs gigaoctets. L'équivalent plus ancien est un StreamReader dans un bloc using avec while ((line = reader.ReadLine()) != null). Évitez ReadAllLines pour les gros fichiers : il charge d'abord toutes les lignes dans un tableau.

Comment vérifier qu'un fichier existe en C# ?

File.Exists(path) renvoie true si le fichier existe et que le programme peut le voir, et Directory.Exists(path) fait de même pour les dossiers. Ne comptez pas dessus pour éviter les exceptions : le fichier peut être supprimé ou verrouillé entre la vérification et la lecture, donc gérez quand même FileNotFoundException et IOException autour de l'opération sur le fichier.

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER