Leçon 10 - Fichiers et Sérialisation
Apprenez à sauvegarder et charger des données avec les fichiers et la sérialisation JSON.
Introduction aux fichiers
La manipulation de fichiers permet de sauvegarder des données de manière persistante. C# offre de nombreuses méthodes pour lire et écrire des fichiers texte, binaires, ou sérialisés.
Lecture et écriture de fichiers texte
Les fichiers texte sont les plus simples à manipuler. Voici les opérations de base :
Écrire dans un fichier
C#
using System;
using System.IO;
// Écrire une ligne dans un fichier (écrase le contenu existant)
File.WriteAllText("message.txt", "Bonjour le monde!");
// Écrire plusieurs lignes
string[] lignes = { "Ligne 1", "Ligne 2", "Ligne 3" };
File.WriteAllLines("liste.txt", lignes);
// Ajouter du texte à la fin du fichier (sans écraser)
File.AppendAllText("message.txt", "\nNouvelle ligne");
Console.WriteLine("✅ Fichiers créés avec succès!");
Lire depuis un fichier
C#
using System;
using System.IO;
// Vérifier si le fichier existe avant de lire
if (File.Exists("message.txt"))
{
// Lire tout le contenu en une fois
string contenu = File.ReadAllText("message.txt");
Console.WriteLine("Contenu du fichier:");
Console.WriteLine(contenu);
// Lire toutes les lignes dans un tableau
string[] lignes = File.ReadAllLines("message.txt");
Console.WriteLine($"\nNombre de lignes: {lignes.Length}");
// Parcourir ligne par ligne
foreach (string ligne in lignes)
{
Console.WriteLine($"- {ligne}");
}
}
else
{
Console.WriteLine("❌ Le fichier n'existe pas");
}
StreamReader et StreamWriter
Pour un contrôle plus fin sur la lecture/écriture, utilisez les streams :
C#
// Écriture avec StreamWriter
using (StreamWriter writer = new StreamWriter("journal.txt", true)) // true = append
{
writer.WriteLine($"{DateTime.Now}: Début de l'application");
writer.WriteLine($"{DateTime.Now}: Opération effectuée");
}
// Lecture avec StreamReader
using (StreamReader reader = new StreamReader("journal.txt"))
{
string ligne;
while ((ligne = reader.ReadLine()) != null)
{
Console.WriteLine(ligne);
}
}
Manipulation de chemins et répertoires
C#
using System.IO;
// Créer un répertoire
string dossier = "MesDonnees";
if (!Directory.Exists(dossier))
{
Directory.CreateDirectory(dossier);
Console.WriteLine($"📁 Dossier '{dossier}' créé");
}
// Chemins combinés de manière sûre
string cheminFichier = Path.Combine(dossier, "donnees.txt");
File.WriteAllText(cheminFichier, "Contenu sauvegardé");
// Obtenir des informations sur un fichier
FileInfo info = new FileInfo(cheminFichier);
Console.WriteLine($"Nom: {info.Name}");
Console.WriteLine($"Taille: {info.Length} octets");
Console.WriteLine($"Créé: {info.CreationTime}");
Console.WriteLine($"Modifié: {info.LastWriteTime}");
// Lister les fichiers d'un dossier
string[] fichiers = Directory.GetFiles(dossier);
Console.WriteLine($"\nFichiers dans '{dossier}':");
foreach (string fichier in fichiers)
{
Console.WriteLine($"- {Path.GetFileName(fichier)}");
}
Sérialisation JSON
JSON est le format standard pour sauvegarder des objets complexes. C# offre System.Text.Json pour cela :
C#
using System;
using System.Text.Json;
using System.IO;
using System.Collections.Generic;
public class Personne
{
public string Nom { get; set; }
public string Prenom { get; set; }
public int Age { get; set; }
public List<string> Hobbies { get; set; }
}
// Créer un objet
Personne personne = new Personne
{
Nom = "Dupont",
Prenom = "Alice",
Age = 28,
Hobbies = new List<string> { "Lecture", "Programmation", "Yoga" }
};
// Sérialiser en JSON avec indentation
JsonSerializerOptions options = new JsonSerializerOptions { WriteIndented = true };
string json = JsonSerializer.Serialize(personne, options);
// Sauvegarder dans un fichier
File.WriteAllText("personne.json", json);
Console.WriteLine("✅ Objet sauvegardé en JSON");
Console.WriteLine(json);
Désérialisation JSON
C#
// Lire depuis le fichier JSON
if (File.Exists("personne.json"))
{
string jsonLu = File.ReadAllText("personne.json");
// Désérialiser en objet C#
Personne personneLue = JsonSerializer.Deserialize<Personne>(jsonLu);
Console.WriteLine("\n📖 Objet chargé depuis JSON:");
Console.WriteLine($"Nom: {personneLue.Prenom} {personneLue.Nom}");
Console.WriteLine($"Âge: {personneLue.Age} ans");
Console.WriteLine("Hobbies:");
foreach (string hobby in personneLue.Hobbies)
{
Console.WriteLine($" - {hobby}");
}
}
Sauvegarder une collection
C#
public class Contact
{
public string Nom { get; set; }
public string Email { get; set; }
public string Telephone { get; set; }
}
public class Carnet
{
public string NomProprietaire { get; set; }
public List<Contact> Contacts { get; set; } = new List<Contact>();
}
// Créer un carnet d'adresses
Carnet carnet = new Carnet
{
NomProprietaire = "Alice Dupont",
Contacts = new List<Contact>
{
new Contact { Nom = "Bob Martin", Email = "bob@example.com", Telephone = "0601020304" },
new Contact { Nom = "Claire Dubois", Email = "claire@example.com", Telephone = "0605060708" }
}
};
// Sauvegarder
string jsonCarnet = JsonSerializer.Serialize(carnet, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText("carnet.json", jsonCarnet);
// Charger
string jsonCharge = File.ReadAllText("carnet.json");
Carnet carnetCharge = JsonSerializer.Deserialize<Carnet>(jsonCharge);
Console.WriteLine($"Carnet de: {carnetCharge.NomProprietaire}");
Console.WriteLine($"Nombre de contacts: {carnetCharge.Contacts.Count}");
Gestion des erreurs avec fichiers :
Toujours entourer les opérations de fichiers d'un try-catch pour gérer les erreurs :
- FileNotFoundException : Fichier introuvable
- UnauthorizedAccessException : Permissions insuffisantes
- IOException : Erreur générale d'entrée/sortie
- JsonException : Format JSON invalide
Exercice pratique
Exercice :
Créez un système de gestion de tâches avec sauvegarde JSON :
- Une classe Tache avec titre, description, priorité, statut, date
- Une classe GestionnaireTaches pour gérer la liste
- Méthodes pour ajouter, supprimer, marquer comme terminée
- Sauvegarde automatique en JSON après chaque modification
- Chargement automatique au démarrage
Gestionnaire de tâches avec persistance JSON
C#
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Linq;
namespace GestionnaireTaches
{
public enum Priorite { Basse, Normale, Haute, Urgente }
public enum StatutTache { AFaire, EnCours, Terminee }
public class Tache
{
public int Id { get; set; }
public string Titre { get; set; }
public string Description { get; set; }
public Priorite Priorite { get; set; }
public StatutTache Statut { get; set; }
public DateTime DateCreation { get; set; }
public DateTime? DateEcheance { get; set; }
public override string ToString()
{
string icone = Statut switch
{
StatutTache.AFaire => "⬜",
StatutTache.EnCours => "🔄",
StatutTache.Terminee => "✅",
_ => ""
};
string prioriteStr = Priorite switch
{
Priorite.Basse => "🟢",
Priorite.Normale => "🟡",
Priorite.Haute => "🟠",
Priorite.Urgente => "🔴",
_ => ""
};
string echeance = DateEcheance.HasValue
? $" - Échéance: {DateEcheance.Value:dd/MM/yyyy}"
: "";
return $"[{Id}] {icone} {prioriteStr} {Titre}{echeance}";
}
}
public class GestionnaireTaches
{
private const string FichierSauvegarde = "taches.json";
private List<Tache> taches;
private int prochainId;
public GestionnaireTaches()
{
taches = new List<Tache>();
prochainId = 1;
Charger();
}
public void AjouterTache(string titre, string description, Priorite priorite, DateTime? dateEcheance = null)
{
Tache nouvelleTache = new Tache
{
Id = prochainId++,
Titre = titre,
Description = description,
Priorite = priorite,
Statut = StatutTache.AFaire,
DateCreation = DateTime.Now,
DateEcheance = dateEcheance
};
taches.Add(nouvelleTache);
Console.WriteLine($"✅ Tâche ajoutée: {nouvelleTache.Titre} (#{nouvelleTache.Id})");
Sauvegarder();
}
public void SupprimerTache(int id)
{
Tache tache = taches.FirstOrDefault(t => t.Id == id);
if (tache != null)
{
taches.Remove(tache);
Console.WriteLine($"🗑️ Tâche supprimée: {tache.Titre}");
Sauvegarder();
}
else
{
Console.WriteLine($"❌ Tâche #{id} introuvable");
}
}
public void ChangerStatut(int id, StatutTache nouveauStatut)
{
Tache tache = taches.FirstOrDefault(t => t.Id == id);
if (tache != null)
{
tache.Statut = nouveauStatut;
Console.WriteLine($"✅ Statut modifié: {tache.Titre} → {nouveauStatut}");
Sauvegarder();
}
else
{
Console.WriteLine($"❌ Tâche #{id} introuvable");
}
}
public void AfficherTaches(StatutTache? filtreStatut = null)
{
var tachesAffichees = filtreStatut.HasValue
? taches.Where(t => t.Statut == filtreStatut.Value)
: taches;
if (!tachesAffichees.Any())
{
Console.WriteLine("📭 Aucune tâche à afficher");
return;
}
Console.WriteLine("\n📋 === LISTE DES TÂCHES ===");
foreach (var tache in tachesAffichees.OrderBy(t => t.Priorite).ThenBy(t => t.DateCreation))
{
Console.WriteLine(tache);
if (!string.IsNullOrWhiteSpace(tache.Description))
{
Console.WriteLine($" {tache.Description}");
}
}
Console.WriteLine("============================\n");
}
public void AfficherStatistiques()
{
int total = taches.Count;
int terminées = taches.Count(t => t.Statut == StatutTache.Terminee);
int enCours = taches.Count(t => t.Statut == StatutTache.EnCours);
int aFaire = taches.Count(t => t.Statut == StatutTache.AFaire);
Console.WriteLine("📊 === STATISTIQUES ===");
Console.WriteLine($"Total: {total} tâche(s)");
Console.WriteLine($"✅ Terminées: {terminées}");
Console.WriteLine($"🔄 En cours: {enCours}");
Console.WriteLine($"⬜ À faire: {aFaire}");
if (total > 0)
{
double pourcentage = (double)terminées / total * 100;
Console.WriteLine($"Progression: {pourcentage:F1}%");
}
Console.WriteLine("========================\n");
}
private void Sauvegarder()
{
try
{
JsonSerializerOptions options = new JsonSerializerOptions { WriteIndented = true };
string json = JsonSerializer.Serialize(taches, options);
File.WriteAllText(FichierSauvegarde, json);
}
catch (Exception ex)
{
Console.WriteLine($"❌ Erreur de sauvegarde: {ex.Message}");
}
}
private void Charger()
{
try
{
if (File.Exists(FichierSauvegarde))
{
string json = File.ReadAllText(FichierSauvegarde);
taches = JsonSerializer.Deserialize<List<Tache>>(json) ?? new List<Tache>();
if (taches.Any())
{
prochainId = taches.Max(t => t.Id) + 1;
Console.WriteLine($"📂 {taches.Count} tâche(s) chargée(s)");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"❌ Erreur de chargement: {ex.Message}");
taches = new List<Tache>();
}
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("📝 === GESTIONNAIRE DE TÂCHES ===");
GestionnaireTaches gestionnaire = new GestionnaireTaches();
// Démonstration
gestionnaire.AjouterTache(
"Finir le projet C#",
"Compléter tous les exercices et tester le code",
Priorite.Haute,
DateTime.Now.AddDays(7)
);
gestionnaire.AjouterTache(
"Faire les courses",
"Acheter du pain, lait, œufs",
Priorite.Normale
);
gestionnaire.AjouterTache(
"Réviser pour l'examen",
"Chapitres 1 à 5",
Priorite.Urgente,
DateTime.Now.AddDays(2)
);
// Afficher toutes les tâches
gestionnaire.AfficherTaches();
// Changer le statut
gestionnaire.ChangerStatut(2, StatutTache.Terminee);
// Afficher les statistiques
gestionnaire.AfficherStatistiques();
Console.WriteLine("\nAppuyez sur une touche pour quitter...");
Console.ReadKey();
}
}
}
Points clés à retenir
- File.WriteAllText/ReadAllText : Méthodes simples pour les fichiers texte
- StreamReader/StreamWriter : Contrôle fin sur la lecture/écriture
- Path.Combine : Toujours combiner les chemins de manière sûre
- JsonSerializer : Sérialisation/désérialisation moderne en C#
- using : Toujours utiliser pour libérer les ressources automatiquement
- Gestion d'erreurs : Toujours prévoir les cas d'erreur avec try-catch