Aller au contenu principal

Gestion de fichiers

Notions théoriques

La classe File — opérations simples

La classe statique File offre des méthodes directes pour les opérations courantes :

// Lire tout le contenu d'un fichier texte
string contenu = File.ReadAllText("notes.txt");

// Lire ligne par ligne (tableau de strings)
string[] lignes = File.ReadAllLines("notes.txt");

// Écrire (écrase le fichier existant)
File.WriteAllText("notes.txt", "Bonjour !");

// Écrire plusieurs lignes
string[] lignes = { "Alice,15.5", "Bob,12.0", "Charlie,9.5" };
File.WriteAllLines("notes.txt", lignes);

// Ajouter à la fin (sans écraser)
File.AppendAllText("journal.txt", $"{DateTime.Now} — Nouvelle entrée\n");

// Vérifier l'existence
if (File.Exists("notes.txt"))
Console.WriteLine("Le fichier existe.");

// Copier, déplacer, supprimer
File.Copy("source.txt", "copie.txt", overwrite: true);
File.Move("ancien.txt", "nouveau.txt");
File.Delete("a_supprimer.txt");

Path.Combine — chemins cross-platform

Ne jamais concaténer les chemins avec + ou /

Windows utilise \ et Linux utilise / comme séparateur. Path.Combine gère automatiquement le bon séparateur selon le système d'exploitation :

// MAUVAIS — ne fonctionnera pas sur tous les OS
string chemin = "dossier" + "\\" + "fichier.txt";

// BON — cross-platform
string chemin = Path.Combine("dossier", "fichier.txt");
// Windows : dossier\fichier.txt
// Linux : dossier/fichier.txt

// Plusieurs niveaux
string chemin = Path.Combine("data", "2024", "janvier", "rapport.csv");

StreamReader / StreamWriter — lecture/écriture en flux

Pour les grands fichiers, utilisez les flux avec using pour la libération automatique des ressources :

// Lecture ligne par ligne (économise la mémoire)
using var reader = new StreamReader("grand_fichier.csv");
string? ligne;
while ((ligne = reader.ReadLine()) != null)
{
Console.WriteLine(ligne);
}
// reader.Dispose() appelé automatiquement ici

// Écriture
using var writer = new StreamWriter("sortie.txt", append: false);
writer.WriteLine("Première ligne");
writer.WriteLine("Deuxième ligne");
// writer.Dispose() + flush automatique ici

Gestion des exceptions

try
{
string contenu = File.ReadAllText("fichier.txt");
Console.WriteLine(contenu);
}
catch (FileNotFoundException)
{
Console.WriteLine("Fichier introuvable.");
}
catch (UnauthorizedAccessException)
{
Console.WriteLine("Accès refusé.");
}
catch (IOException ex)
{
Console.WriteLine($"Erreur d'entrée/sortie : {ex.Message}");
}

Obtenir des infos sur un fichier

string chemin = "notes.txt";

if (File.Exists(chemin))
{
var info = new FileInfo(chemin);
Console.WriteLine($"Taille : {info.Length} octets");
Console.WriteLine($"Créé : {info.CreationTime}");
Console.WriteLine($"Modifié: {info.LastWriteTime}");
Console.WriteLine($"Nom : {info.Name}");
Console.WriteLine($"Dossier: {info.DirectoryName}");
}

Exemple pratique

// Lecture d'un fichier CSV de produits et génération d'un rapport
string fichierEntree = Path.Combine("data", "produits.csv");
string fichierSortie = Path.Combine("data", "rapport.txt");

// Contenu du CSV simulé
string csvContenu = """
Clavier mécanique,69.99,5
Souris ergonomique,49.99,0
Câble USB-C 2m,9.99,12
Webcam HD,89.99,2
Casque audio,59.99,0
""";
File.WriteAllText(fichierEntree, csvContenu);

// Lecture et traitement
var rapportLignes = new List<string>();
rapportLignes.Add("=== Rapport de stock ===");
rapportLignes.Add($"Généré le {DateTime.Now:dd/MM/yyyy HH:mm}");
rapportLignes.Add(new string('-', 40));

int nbRuptures = 0;
string[] lignes = File.ReadAllLines(fichierEntree);

foreach (string ligne in lignes)
{
string[] champs = ligne.Split(',');
if (champs.Length < 3) continue;

string nom = champs[0];
decimal prix = decimal.Parse(champs[1]);
int stock = int.Parse(champs[2]);

string statut = stock == 0 ? "RUPTURE" : $"{stock} unité(s)";
rapportLignes.Add($" {nom,-25} {prix,8:F2}{statut}");

if (stock == 0) nbRuptures++;
}

rapportLignes.Add(new string('-', 40));
rapportLignes.Add($" {nbRuptures} produit(s) en rupture de stock.");

// Écriture du rapport
File.WriteAllLines(fichierSortie, rapportLignes);
Console.WriteLine($"Rapport généré : {fichierSortie}");

// Affichage
foreach (string l in rapportLignes)
Console.WriteLine(l);

Test de mémorisation/compréhension


Quelle méthode lit tout le contenu d'un fichier texte en une seule chaîne ?


Pourquoi utiliser `Path.Combine` plutôt que de concaténer les chemins ?


Quel avantage a `using var reader = new StreamReader(...)` ?


Quelle méthode ajoute du texte à la fin d'un fichier sans l'écraser ?


Quelle exception est levée quand on tente de lire un fichier qui n'existe pas ?


TP pour réfléchir et résoudre des problèmes

Vous allez lire un fichier CSV de produits et générer un rapport de stock.

Étape 1 — Créer et lire le fichier CSV

Créez un fichier CSV puis lisez-le ligne par ligne.


Bonne pratique - Vérifier l'existence avant de lire

Vérifier File.Exists() avant File.ReadAllText/Lines permet d'afficher un message d'erreur clair plutôt qu'une FileNotFoundException. Cela améliore l'expérience utilisateur et simplifie le débogage.

Étape 2 — Analyser chaque ligne CSV

Découpez chaque ligne et extrayez les données.


Bonne pratique - Toujours Trim() après Split()

Un CSV peut avoir des espaces autour des virgules ("Clavier , 49.99"). Appelez .Trim() sur chaque champ après le découpage pour nettoyer ces espaces et éviter des erreurs de parsing.

Étape 3 — Sauvegarder le rapport

Écrivez le rapport dans un fichier texte.


Bonne pratique - Séparer lecture et écriture

Lisez d'abord toutes les données, traitez-les en mémoire, puis écrivez le résultat. Évitez de lire et d'écrire dans le même fichier simultanément — cela peut corrompre les données et est difficile à déboguer.

📌 Une solution