1. Introduction
Travailler directement avec les streams (StreamReader, StreamWriter, FileStream) est très utile, surtout lorsqu'il faut contrôler le processus de lecture/écriture à bas niveau : par exemple, écrire des blocs « petit à petit » ou traiter de gros fichiers par parties.
Mais dans la vraie vie, il arrive souvent qu'on ait juste besoin de savoir : « ce fichier existe-t-il ? », « copier un fichier d'un endroit à un autre », « supprimer un fichier », « obtenir la liste de tous les fichiers .txt dans un dossier », etc. Pour ces tâches Microsoft a créé deux outils universels : les classes statiques File et Directory. Statiques — ça veut dire qu'on n'a pas besoin d'instancier, on appelle directement la méthode sur le nom de la classe.
Analogie de la vie courante
Si les streams sont vous avec un crayon qui écrit soigneusement chaque lettre sur une feuille, alors File et Directory sont votre bureau avec des tiroirs : vous pouvez « instantanément » ouvrir un tiroir (Directory), en sortir une feuille (File.ReadAllText), jeter la feuille (File.Delete) ou même sortir tout un tiroir et l'envoyer à l'autre bout de la pièce (Directory.Move). Tâches simples — méthodes simples.
2. La classe File : qu'est-ce que c'est et à quoi ça sert
La classe File fournit un ensemble très pratique de méthodes statiques pour toutes les opérations populaires sur les fichiers.
Méthodes les plus souvent utilisées
| Méthode | Description |
|---|---|
|
Vérifie si le fichier existe à ce chemin |
|
Lit tout le fichier en tant que texte |
|
Lit toutes les lignes du fichier dans un tableau |
|
Réécrit le fichier en y écrivant le texte |
|
Ajoute du texte à la fin du fichier |
|
Copie le fichier |
|
Supprime le fichier |
|
Déplace ou renomme le fichier |
|
Ouvre un stream pour des opérations complexes |
Exemple rapide : vérifier le fichier et le lire
string filePath = "data.txt";
if (File.Exists(filePath))
{
string content = File.ReadAllText(filePath);
Console.WriteLine("Contenu du fichier :");
Console.WriteLine(content);
}
else
{
Console.WriteLine("Fichier introuvable !");
}
Vous voyez ? Aucun gestion manuel de streams pour un cas simple !
3. La classe Directory : gérer les dossiers sans douleur
Si File concerne les fichiers individuels, alors Directory concerne les dossiers (directories).
Tâches principales
| Méthode | Description |
|---|---|
|
Vérifie si le dossier existe |
|
Crée un dossier (ou un chemin avec tous les dossiers intermédiaires) |
|
Supprime le dossier (possibilité avec sous-répertoires) |
|
Obtient la liste des fichiers dans le dossier |
|
Obtient la liste des sous-répertoires |
|
Déplace ou renomme le dossier |
|
Obtenir le répertoire de travail courant de l'application |
Exemple : créer un dossier et y sauvegarder un fichier
string dirPath = "Results";
if (!Directory.Exists(dirPath))
{
Directory.CreateDirectory(dirPath);
Console.WriteLine("Dossier 'Results' créé.");
}
string filePath = Path.Combine(dirPath, "summary.txt");
File.WriteAllText(filePath, "Données finales : ...");
Console.WriteLine($"Fichier {filePath} enregistré.");
4. Scénarios typiques d'utilisation de File et Directory
Les méthodes de base peuvent sembler ennuyeuses si on ne les voit pas en action ! Voyons comment utiliser ces classes pour résoudre des tâches réelles et, en même temps, continuons le développement de notre application hypothétique (imaginons que nous faisons un simple système de todo-list — les résultats sont sauvegardés dans des fichiers).
Sauvegarder des données dans un fichier (remplacer l'ancien fichier)
// Sauvegarde de la liste de tâches dans un fichier
string[] todos = { "Acheter du pain", "Appeler le médecin", "Faire le devoir de C#" };
string filePath = "todo.txt";
File.WriteAllLines(filePath, todos);
Console.WriteLine("Liste de tâches sauvegardée.");
Charger les données depuis un fichier
// Charger les tâches si le fichier existe
if (File.Exists(filePath))
{
string[] loadedTodos = File.ReadAllLines(filePath);
Console.WriteLine("Votre liste de tâches :");
foreach (var task in loadedTodos)
{
Console.WriteLine("- " + task);
}
}
else
{
Console.WriteLine("Vous n'avez pas encore de liste de tâches.");
}
Ajouter une nouvelle tâche (sans réécrire le fichier)
string newTask = "Promener le chien";
File.AppendAllText(filePath, newTask + Environment.NewLine);
Console.WriteLine("Tâche ajoutée !");
Copie et sauvegarde de secours du fichier
string backupPath = "todo_backup.txt";
File.Copy(filePath, backupPath, overwrite: true);
Console.WriteLine("Sauvegarde de la liste de tâches créée.");
Déplacer (ou renommer) le fichier
string archivePath = "todo_archive.txt";
File.Move(filePath, archivePath);
Console.WriteLine("Liste de tâches archivée (renommée).");
Supprimer le fichier
if (File.Exists(archivePath))
{
File.Delete(archivePath);
Console.WriteLine("Archive supprimée — on libère de l'espace !");
}
5. Travailler avec les dossiers : exemples
Créer une hiérarchie de répertoires
string path = Path.Combine("Reports", "2024", "June");
Directory.CreateDirectory(path);
Console.WriteLine($"Dossier {path} créé (y compris les dossiers intermédiaires).");
Obtenir la liste des fichiers et dossiers
string dirPath = "Reports";
if (Directory.Exists(dirPath))
{
string[] files = Directory.GetFiles(dirPath);
Console.WriteLine("Fichiers dans le dossier :");
foreach (var file in files)
{
Console.WriteLine(file);
}
string[] subDirs = Directory.GetDirectories(dirPath);
Console.WriteLine("Sous-répertoires :");
foreach (var dir in subDirs)
{
Console.WriteLine(dir);
}
}
Filtrer les fichiers par masque (seulement txt)
string[] txtFiles = Directory.GetFiles(dirPath, "*.txt");
Console.WriteLine("Uniquement les fichiers .txt :");
foreach (var file in txtFiles)
{
Console.WriteLine(file);
}
Parcours récursif (fichiers dans tous les sous-dossiers)
string[] allFiles = Directory.GetFiles(dirPath, "*.*", SearchOption.AllDirectories);
Console.WriteLine("Fichiers dans tous les dossiers imbriqués :");
foreach (var file in allFiles)
{
Console.WriteLine(file);
}
Déplacer et supprimer des répertoires
string from = "OldReports";
string to = "Archive/OldReports";
if (Directory.Exists(from))
{
Directory.Move(from, to);
Console.WriteLine($"Dossier {from} déplacé vers {to}");
}
if (Directory.Exists(to))
{
Directory.Delete(to, recursive: true); // true : tout supprimer à l'intérieur
Console.WriteLine($"Dossier {to} supprimé (avec tout son contenu).");
}
6. Nuances utiles
Intégration avec les chemins : la classe Path
Quand on travaille avec des fichiers et dossiers, il faut souvent composer des chemins complets, concaténer des noms de répertoires et de fichiers, extraire des extensions, vérifier les caractères autorisés. Pour ça on utilise la classe utilitaire Path.
Exemples
string folder = "Results";
string filename = "week1.txt";
string fullPath = Path.Combine(folder, filename); // combinaison sûre !
Console.WriteLine(fullPath); // "Results/week1.txt" (ou "\" sur Windows)
- Obtenir l'extension du fichier : Path.GetExtension(fullPath)
- Obtenir le nom du fichier sans le chemin : Path.GetFileName(fullPath)
Utilisez Path.Combine au lieu de concaténer des chaînes — c'est plus sûr pour des applications cross-platform.
Méthodes « tout en une fois » vs variante stream
Beaucoup de méthodes de File et Directory (par exemple, File.ReadAllText, File.WriteAllText, Directory.GetFiles) font le boulot « en une fois » : elles lisent/écrivent/obtiennent la liste des fichiers en une seule opération. C'est TRÈS pratique, mais ça ne convient pas pour des fichiers ou des répertoires très volumineux où la mémoire peut manquer. Si vous traitez des gigaoctets — passez aux classes stream (StreamReader, StreamWriter, FileStream, etc.) ou au traitement par morceaux.
Quand utiliser File/Directory, et quand utiliser les classes de streams
| Situation | Que choisir |
|---|---|
| Il faut vérifier si un fichier/dossier existe | |
| Lire/écrire un petit fichier entier | |
| Ajouter du texte à la fin d'un fichier | |
| Obtenir la liste des fichiers dans un répertoire | |
| Copier, supprimer, déplacer un fichier | |
| Copier/supprimer un dossier entier | Directory.Delete/Move/Copy (Copy — avec une bibliothèque tierce) |
| Traiter des fichiers TRÈS volumineux par parties | Classes stream (StreamReader, FileStream) |
Signification pratique et applications réelles
- Chargement/sauvegarde rapides de configurations, paramètres, fichiers JSON/XML.
- Systèmes de logging (écriture des logs sur disque).
- Outils simples de sauvegarde (backup) et migration de données.
- Scan de dossiers contenant multimédia, photos, documents.
- Scénarios utilisateurs : chargement de templates, export/import, génération de rapports, etc.
Les exercices pratiques lors d'entretiens demandent souvent d'utiliser ces classes : « Implémentez une fonction qui calcule la taille totale de tous les fichiers .txt dans un répertoire », « Faites une sauvegarde des fichiers dans un dossier séparé », etc.
Aide-mémoire visuel : quel méthode utiliser selon le cas
graph TD
A[Que voulez-vous faire ?]
A -->|Vérifier existence| B[File.Exists ou Directory.Exists]
A -->|Lire/écrire fichier en entier| C[File.ReadAllText/WriteAllText]
A -->|Ajouter des données au fichier| D[File.AppendAllText]
A -->|Travailler avec des dossiers| E[Directory.CreateDirectory, GetFiles, GetDirectories]
A -->|Copier/supprimer/déplacer un fichier| F[File.Copy/Delete/Move]
A -->|Copier/supprimer dossier entier| G[Directory.Delete/Move]
7. Particularités et erreurs typiques
Vérification d'existence et « condition de course ». Même si vous vérifiez qu'un fichier/dossier existe, entre cette vérification et l'opération réelle un autre processus peut tout changer. Donc utilisez toujours try-catch même si vous avez déjà vérifié l'existence !
Droits d'accès. Si l'application n'a pas les droits de lecture/écriture/suppression, les méthodes lanceront UnauthorizedAccessException.
Chemin trop long. Longueur maximale des chemins (généralement 260 caractères sur les anciens Windows ; dans .NET 9 les limites sont plus souples, mais restez prudent).
Gestion des erreurs. Des méthodes comme File.ReadAllText ou Directory.GetFiles ne pardonnent pas les erreurs : si le fichier/dossier est manquant — elles lèvent une exception immédiatement. Enveloppez-les dans un try-catch ou vérifiez l'existence au préalable.
GO TO FULL VERSION