1. Introduction
Imagine un archive de photos sur plusieurs années — des milliers de fichiers dans un seul dossier (classique chez les utilisateurs Windows), et maintenant imagine la tâche : copier seulement les fichiers .jpg qui ont été créés cette année dans un dossier séparé pour traitement. Ou tu dois renommer tous les rapports avec le préfixe "old_" pour différencier l'ancienne et la nouvelle version. Même si tu n'es pas fan des archives photo, les opérations en masse sont utiles dans presque tous les projets de traitement de données, logs, backups ou automatisation. Elles tombent aussi souvent en entretien technique !
Les opérations en masse sont un super prétexte pour maîtriser :
- Boucles et LINQ pour parcourir le contenu des répertoires
- Pratique de la gestion des chemins (Path)
- Bases du filtrage, de la recherche, du renommage par motif
- Points importants : sécurité, erreurs, écrasements
Allons-y — que la force soit avec toi pour dompter le chaos des fichiers !
2. Copie en masse de fichiers
Principes : comment ça marche
Pour une opération en masse il faut généralement :
- Obtenir la liste des fichiers voulus (par exemple, tous les .txt dans un dossier)
- Pour chaque fichier effectuer l'action nécessaire (copier, supprimer, etc.)
On peut réaliser ça avec :
- Directory.GetFiles() — récupérer la liste des fichiers,
- Une boucle foreach — parcourir chaque fichier et effectuer l'opération voulue.
Exemple : copier tous les fichiers .txt d'un dossier vers un autre
string sourceDir = @"C:\Source";
string destDir = @"C:\Target";
// On récupère la liste de tous les fichiers .txt dans le dossier source
string[] txtFiles = Directory.GetFiles(sourceDir, "*.txt");
foreach (string srcPath in txtFiles)
{
// On récupère uniquement le nom de fichier à partir du chemin complet
string fileName = Path.GetFileName(srcPath);
// On construit le chemin complet pour le fichier dans le dossier cible
string destPath = Path.Combine(destDir, fileName);
// On copie le fichier
File.Copy(srcPath, destPath, overwrite: true); // overwrite - si le fichier existe déjà, remplacer
Console.WriteLine($"Copied: {fileName}");
}
Console.WriteLine("Tous les fichiers .txt ont été copiés avec succès !");
Remarque : dans cet exemple on utilise le filtre "*.txt" — c'est un motif de recherche de noms de fichiers, comme sous Windows.
Visualisation (schéma)
+----------------+ [*.txt] +----------------+
| C:\Source | ---filter-----> | C:\Target |
| a.txt | foreach + | |
| b.txt | --copy--------> | a.txt (copied) |
| c.jpg | | b.txt (copied) |
+----------------+ +----------------+
(les fichiers .jpg sont ignorés, seuls les .txt sont copiés)
3. Suppression en masse de fichiers
La suppression en masse est une opération très courante. Par exemple, il faut souvent nettoyer les fichiers temporaires, supprimer automatiquement les vieux logs ou des photos jpg dont on n'a plus besoin.
Exemple : supprimer tous les fichiers plus vieux que 30 jours
string dir = @"C:\MyLogs";
int daysOld = 30;
DirectoryInfo di = new DirectoryInfo(dir);
// On obtient tous les fichiers dans le dossier
foreach (FileInfo file in di.GetFiles())
{
// On vérifie la date de dernière modification
if (file.LastWriteTime < DateTime.Now.AddDays(-daysOld))
{
file.Delete();
Console.WriteLine($"Supprimé : {file.Name}");
}
}
Astuce : FileInfo.LastWriteTime — hyper pratique pour tester "plus ancien que N jours".
4. Renommage en masse de fichiers
Parfois il faut renommer plein de fichiers selon un motif. Par exemple, ajouter un préfixe commun, changer des extensions, ou simplement numéroter tout ça. En .NET c'est le même principe — on récupère la liste des fichiers, puis on renomme avec File.Move().
Exemple : ajouter le préfixe "old_" à tous les fichiers .docx
string dir = @"C:\Reports";
string[] docxFiles = Directory.GetFiles(dir, "*.docx");
foreach (string oldPath in docxFiles)
{
string dirPath = Path.GetDirectoryName(oldPath)!;
string fileName = Path.GetFileName(oldPath);
string newPath = Path.Combine(dirPath, "old_" + fileName);
// On renomme (en pratique, c'est un déplacement "dans le même dossier avec un nouveau nom")
File.Move(oldPath, newPath);
Console.WriteLine($"Renommé : {fileName} -> old_{fileName}");
}
Point important : si le dossier contient déjà un fichier avec le nouveau nom, une exception sera levée. On peut la gérer via try-catch si nécessaire.
5. Copier des répertoires entiers avec leur contenu
Pour des opérations simples sur un seul dossier il n'y a pas de méthode "copier tout le dossier" en une ligne (Directory.Copy n'existe pas — c'est un piège pour les Jedi !). Il faut copier manuellement :
- Créer le dossier cible (s'il n'existe pas)
- Copier tous les fichiers (voir l'exemple qu'on connaît)
- Copier récursivement tous les sous-dossiers (chacun traité comme une nouvelle tâche de copie)
Fonction universelle : copie récursive d'un dossier
using System;
using System.IO;
class Program
{
static void CopyDirectory(string sourceDir, string destDir, bool overwrite = true)
{
// On crée le dossier s'il n'existe pas
Directory.CreateDirectory(destDir);
// On copie tous les fichiers
foreach (string filePath in Directory.GetFiles(sourceDir))
{
string fileName = Path.GetFileName(filePath);
string destFile = Path.Combine(destDir, fileName);
File.Copy(filePath, destFile, overwrite);
}
// On copie tous les sous-dossiers (récursivement)
foreach (string subDir in Directory.GetDirectories(sourceDir))
{
string dirName = Path.GetFileName(subDir);
string destSubDir = Path.Combine(destDir, dirName);
CopyDirectory(subDir, destSubDir, overwrite);
}
}
static void Main()
{
string source = @"C:\Archive2023";
string target = @"D:\Backup2023";
CopyDirectory(source, target);
Console.WriteLine("Répertoire copié avec succès !");
}
}
Schéma
CopyDirectory(A, B)
/ \
copy files foreach subDir -> CopyDirectory(subDir, destSubDir)
6. Filtrage, recherche et traitement en masse
Supposons que tu veuilles non seulement parcourir un dossier, mais filtrer selon plusieurs critères : par exemple, seulement les images dont la taille dépasse 5 Mo et qui ont été créées en 2024 ! Pour ça il est pratique de combiner LINQ avec les classes du système de fichiers.
Exemple : afficher les noms des images volumineuses et récentes
string dir = @"C:\Pictures";
var filtered = new DirectoryInfo(dir)
.GetFiles("*.jpg")
.Where(f => f.Length > 5_000_000 && f.CreationTime.Year == 2024);
foreach (var file in filtered)
{
Console.WriteLine($"{file.Name} ({file.Length / 1024 / 1024} Mo)");
}
Dans cet exemple on utilise LINQ pour chaîner les filtres — et on écrit du code réaliste qu'on retrouve en production.
7. Parcours des dossiers imbriqués : récursion et itération
Souvent il faut traiter non seulement un répertoire, mais toute son arborescence (par exemple, supprimer tous les fichiers temporaires dans toute la structure). Les méthodes de récupération de fichiers (Directory.GetFiles et DirectoryInfo.GetFiles) ont une variante avec le paramètre spécial SearchOption.AllDirectories, qui s'en occupe pour toi !
Exemple : trouver et supprimer tous les fichiers .tmp dans tous les sous-dossiers
string root = @"D:\BigFolder";
string[] tmpFiles = Directory.GetFiles(root, "*.tmp", SearchOption.AllDirectories);
foreach (string file in tmpFiles)
{
File.Delete(file);
Console.WriteLine($"Supprimé : {file}");
}
Console.WriteLine("Tous les fichiers temporaires ont été supprimés.");
Attention : fais gaffe avec ce flag — il peut trouver des fichiers même dans des imbriquations très profondes !
8. Création en masse de fichiers et dossiers
Parfois la tâche est inverse — créer automatiquement une arborescence ou générer beaucoup de fichiers.
Exemple : création de 10 dossiers et 10 fichiers dans chacun
string root = @"C:\GeneratedFolders";
for (int i = 1; i <= 10; i++)
{
string subDir = Path.Combine(root, $"Folder_{i}");
Directory.CreateDirectory(subDir);
for (int j = 1; j <= 10; j++)
{
string filePath = Path.Combine(subDir, $"File_{j}.txt");
File.WriteAllText(filePath, $"Ceci est le fichier numéro {j} dans le dossier {i}");
}
}
Console.WriteLine("Dossiers et fichiers créés !");
Astuce : c'est un moyen rapide de préparer une infra de test, de générer des données factices pour les tests, l'apprentissage, etc.
9. Déplacement en masse de fichiers
Comme pour la copie, mais on utilise File.Move à la place de File.Copy. Pratique pour trier des fichiers dans des dossiers.
Exemple : trier les fichiers par extension
Imaginons : dans un dossier il y a plein de types de fichiers, et tu veux les répartir dans des dossiers .jpg, .pdf, .docx, etc.
string source = @"C:\Downloads";
string[] files = Directory.GetFiles(source);
foreach (string path in files)
{
string ext = Path.GetExtension(path).TrimStart('.').ToUpper(); // "JPG", "PDF", "DOCX"
if (string.IsNullOrEmpty(ext)) ext = "OTHER";
string destDir = Path.Combine(source, ext);
Directory.CreateDirectory(destDir); // pas grave si ça existe déjà
string fileName = Path.GetFileName(path);
string destPath = Path.Combine(destDir, fileName);
if (!File.Exists(destPath))
{
File.Move(path, destPath);
Console.WriteLine($"Déplacé : {fileName} -> {destDir}");
}
else
{
Console.WriteLine($"Le fichier existe déjà dans {destDir}, on passe : {fileName}");
}
}
Les fichiers seront rangés "par boîte", et tu te sentiras comme la Marie Kondo digitale.
10. Erreurs typiques et subtilités des opérations en masse
Quand tu travailles sur des centaines de fichiers, des détails intéressants apparaissent.
Par exemple, certains fichiers peuvent être ouverts par une autre application — tenter de les supprimer ou copier provoquera une erreur. Il arrive aussi qu'un fichier existe déjà dans le dossier cible avec le même nom. Si le code ne prévoit pas d'écrasement, une exception sera levée. Parfois tu peux ne pas avoir les droits sur certains fichiers ou dossiers, ou supprimer quelque chose d'important par erreur en mode récursif.
L'erreur classique est d'exécuter les opérations sans gestion d'erreurs : si un plantage survient au milieu (par exemple, absence de droits sur un fichier), la boucle s'arrêtera et les fichiers suivants ne seront pas traités. Pour des opérations fiables on met généralement un try-catch à l'intérieur de la boucle, afin de sauter le fichier problématique et continuer le reste.
Et n'oublie pas les paramètres d'écrasement : là où c'est pertinent, utilise overwrite: true dans File.Copy, et pour les renommages/déplacements vérifie d'avance l'existence du fichier cible ou adopte une stratégie de résolution de conflits (ajout d'un suffixe, passer, journaliser).
GO TO FULL VERSION