CodeGym /Cours /C# SELF /Copie de fichiers et de répertoires

Copie de fichiers et de répertoires

C# SELF
Niveau 40, Leçon 2
Disponible

1. Copie de fichiers

Jusqu'à présent nos opérations sur le système de fichiers ressemblaient à des «coups uniques» : créer un fichier, lire, supprimer — et c'est tout. Mais dans le monde réel il arrive souvent qu'il faille copier du contenu : sauvegarder des documents, dupliquer des templates, automatiser le traitement des données. La copie paraît une tâche d'enfant (Ctrl+C et Ctrl+V — notre truc), mais en réalité il y a beaucoup de subtilités.

Aujourd'hui on va voir toutes les façons de copier fichiers et dossiers — des plus simples aux un peu plus complexes. On verra aussi comment les classes intégrées de .NET gèrent ça, quelles sont les limites, quelles erreurs peuvent vous attendre et que faire si votre répertoire contient deux mille dossiers et un million de fichiers.

La classe File et la méthode Copy

Le moyen le plus simple de copier un fichier est d'utiliser la méthode statique File.Copy. Cette méthode prend le chemin du fichier source, le chemin du nouveau fichier et un paramètre optionnel : autoriser la réécriture si le fichier existe déjà.

using System.IO;

// Exemple simple de copie de fichier
File.Copy("source.txt", "destination.txt");

Si le fichier de destination existe déjà, la méthode lancera une exception. Pour autoriser explicitement la réécriture, utilisez le troisième paramètre :

File.Copy("source.txt", "destination.txt", overwrite: true);

Point important : Si le deuxième paramètre ("destination.txt") est le chemin d'un répertoire existant, et non d'un fichier, une erreur surviendra. La méthode attend un chemin vers un fichier !

Travail avec les chemins

Comme d'habitude, n'oubliez pas d'utiliser Path.Combine pour ne pas vous faire avoir par des barres obliques en double ou inversées :

string sourcePath = Path.Combine("Data", "input.txt");
string destPath = Path.Combine("Backup", "input_backup.txt");

File.Copy(sourcePath, destPath, overwrite: true);

Gestion des erreurs

Qu'est-ce qui peut mal tourner lors de la copie d'un fichier ? Beaucoup de choses : le fichier peut être occupé par un autre processus, le fichier source peut manquer, vous pouvez ne pas avoir les permissions, le disque de destination peut être plein. Utilisez la gestion des exceptions :

try
{
    File.Copy("bigdata.txt", "bigdata_backup.txt", overwrite: false);
    Console.WriteLine("Le fichier a été copié avec succès !");
}
catch (IOException ex)
{
    Console.WriteLine($"Erreur d'entrée/sortie : {ex.Message}");
}
catch (UnauthorizedAccessException)
{
    Console.WriteLine("Pas d'accès au fichier ou au dossier.");
}
catch (Exception ex)
{
    Console.WriteLine($"Autre erreur : {ex.Message}");
}

La classe FileInfo et la méthode CopyTo

Si vous avez déjà un objet FileInfo, vous pouvez appeler sa méthode CopyTo :

var fi = new FileInfo("report.xlsx");
fi.CopyTo("backup_report.xlsx");

Le troisième argument (overwrite) dans CopyTo n'est apparu qu'à partir de .NET Core 2.0+, donc si vous codez pour une vieille version du framework — ne soyez pas surpris par une erreur.

Copier un fichier «dans le vide» (ou «pas vu — pas pris»)

Faites attention au chemin indiqué pour la copie. Si le dossier de destination n'existe pas, .NET lèvera une erreur. Donc avant de copier un fichier il est préférable de s'assurer que le répertoire de destination existe :

string backupDir = "Backup";
if (!Directory.Exists(backupDir))
{
    Directory.CreateDirectory(backupDir);
}

string targetPath = Path.Combine(backupDir, "mydoc.txt");
File.Copy("mydoc.txt", targetPath);

2. Copie de répertoires : tâche pour les âmes courageuses

Là commencent les vraies aventures ! .NET n'a pas de méthode «magique» intégrée Directory.Copy qui ferait tout en une ligne (comme pour la classe File). Il faudra un peu de boulot et écrire une fonction pour copier récursivement tous les fichiers et sous-dossiers.

Pourquoi il n'existe pas de Directory.Copy ?

Copier des répertoires n'est pas toujours trivial. Il faut tenir compte que chaque dossier peut contenir des fichiers, des sous-dossiers, des fichiers cachés, des fichiers avec des permissions spéciales et des chemins longs. Les développeurs de .NET ont donc dit : «laissez les programmeurs décider ce qu'ils veulent copier.» Mais on n'aime pas les solutions faciles — on va écrire notre fonction !

Exemple de copie récursive d'un répertoire

Tâche : copier le contenu d'un dossier (et tout son sous-univers) dans un autre.

using System;
using System.IO;

void CopyDirectory(string sourceDir, string destDir, bool recursive)
{
    // Vérifie si le dossier source existe
    if (!Directory.Exists(sourceDir))
        throw new DirectoryNotFoundException($"Dossier source introuvable : {sourceDir}");

    // Crée le dossier de destination s'il n'existe pas encore
    if (!Directory.Exists(destDir))
        Directory.CreateDirectory(destDir);

    // Copie tous les fichiers
    foreach (string filePath in Directory.GetFiles(sourceDir))
    {
        string fileName = Path.GetFileName(filePath);
        string destFilePath = Path.Combine(destDir, fileName);
        File.Copy(filePath, destFilePath, overwrite: true);
    }

    // Si récursif — copie tous les sous-dossiers
    if (recursive)
    {
        foreach (string dirPath in Directory.GetDirectories(sourceDir))
        {
            string dirName = Path.GetFileName(dirPath);
            string destSubDir = Path.Combine(destDir, dirName);
            // Appel récursif !
            CopyDirectory(dirPath, destSubDir, recursive);
        }
    }
}

Utilisation :

CopyDirectory("C:\\MyData", "D:\\Backup\\MyData", recursive: true);

Cette fonction crée la structure de répertoires et copie tous les fichiers, y compris le contenu des sous-dossiers.

Analysons le code et les subtilités

On commence par créer le répertoire de destination (s'il n'existe pas) — sinon en essayant de copier un fichier on recevra une erreur. À l'intérieur de chaque boucle on utilise Path.GetFileName pour ne pas perdre le nom du fichier ou du dossier en construisant le nouveau chemin.

Au fait, si vous copiez un répertoire dans lui-même ou dans un de ses sous-dossiers, vous obtiendrez une récursion épique… et un StackOverflowException. Ne copiez pas "C:\\Data" dans "C:\\Data\\Backup". L'ordinateur va s'en vexer !

Copier seulement les fichiers (sans les sous-dossiers)

Parfois il suffit de copier seulement les fichiers du niveau supérieur (sans plonger dans les sous-dossiers) :

void CopyFilesOnly(string sourceDir, string destDir)
{
    if (!Directory.Exists(destDir))
        Directory.CreateDirectory(destDir);

    foreach (string filePath in Directory.GetFiles(sourceDir))
    {
        string fileName = Path.GetFileName(filePath);
        string destFilePath = Path.Combine(destDir, fileName);
        File.Copy(filePath, destFilePath, overwrite: true);
    }
}

Exemple — implémentons une sauvegarde

Ajoutons cette fonctionnalité à notre «Application Maison» que nous développons tout au long du cours. Que l'application sache maintenant faire une copie de sauvegarde de ses données.

using System;
using System.IO;

namespace HomeApp
{
    class Program
    {
        static void CopyDirectory(string sourceDir, string destDir, bool recursive)
        {
            if (!Directory.Exists(sourceDir))
                throw new DirectoryNotFoundException($"Dossier source introuvable : {sourceDir}");

            if (!Directory.Exists(destDir))
                Directory.CreateDirectory(destDir);

            foreach (string filePath in Directory.GetFiles(sourceDir))
            {
                string fileName = Path.GetFileName(filePath);
                string destFilePath = Path.Combine(destDir, fileName);
                File.Copy(filePath, destFilePath, overwrite: true);
            }

            if (recursive)
            {
                foreach (string dirPath in Directory.GetDirectories(sourceDir))
                {
                    string dirName = Path.GetFileName(dirPath);
                    string destSubDir = Path.Combine(destDir, dirName);
                    CopyDirectory(dirPath, destSubDir, recursive);
                }
            }
        }

        static void Main(string[] args)
        {
            Console.WriteLine("Entrez le chemin du répertoire de travail :");
            string source = Console.ReadLine()!;
            Console.WriteLine("Entrez le chemin du dossier pour la sauvegarde :");
            string dest = Console.ReadLine()!;

            try
            {
                CopyDirectory(source, dest, recursive: true);
                Console.WriteLine("La sauvegarde a été créée avec succès !");
            }
            catch (Exception ex)
            {
                Console.WriteLine("Erreur lors de la copie : " + ex.Message);
            }
        }
    }
}

3. Astuces utiles

Comparaison : fichier vs répertoire — tableau

Fichier Répertoire
Méthode intégrée
File.Copy
-
Orienté objet
FileInfo.CopyTo
-
Parcours de la hiérarchie Pas nécessaire Nécessite la récursion
Création de la structure Automatique Doit créer manuellement la hiérarchie
Danger de récursion Non Oui — ne pas copier «soi-même»

Application pratique et exercices pour pratiquer

Les tâches de copie de fichiers et de dossiers sont partout : de la sauvegarde à la migration de données ou à la mise à jour de ressources dans des launchers de jeux. La plupart du temps ces procédures sont automatisées pour éviter le travail manuel et le classique «oh, j'ai oublié un fichier !» le lundi matin.

La copie de répertoires est utile dans tous les scénarios où il faut conserver non seulement le contenu, mais aussi la «charpente» de la structure, incluant les sous-dossiers, fichiers imbriqués, paramètres.

Checklist pour la copie (pour ne pas se planter)

  • Existence de la source
  • Existence du dossier de destination (le créer si besoin via Directory.CreateDirectory)
  • Scénario de réécriture des fichiers — faut-il overwrite: true ?
  • Ne copiez-vous pas le dossier «dans lui-même» ?
  • Ne dépassez-vous pas la longueur maximale des chemins (surtout sur Windows) ?
  • Prenez-vous en compte les fichiers cachés/système ?

4. Particularités et erreurs typiques lors de la copie

Permissions

La copie peut échouer si votre programme n'a pas les droits de lecture sur les sources ou d'écriture dans le dossier de destination. Dans ce cas vous obtiendrez une des variantes de UnauthorizedAccessException. La solution — lancer le programme en tant qu'administrateur (seulement si nécessaire !) ou choisir des dossiers appropriés pour la copie.

Fichiers occupés

Si un fichier est ouvert dans une autre application (par exemple Excel le verrouille), File.Copy peut lancer une exception. Assurez-vous que l'application qui bloque le fichier ne gêne pas le processus, ou implémentez une logique de retentatives (try-catch avec retries).

Réécriture des fichiers

Quelle logique choisir : écraser les fichiers de destination ou ne pas y toucher s'ils existent ? Pour les sauvegardes il est généralement pertinent d'écraser (overwrite: true), et pour la duplication de templates — non (overwrite: false).

Copie des fichiers cachés et système

Par défaut les méthodes que nous avons utilisées (Directory.GetFiles) retournent tous les fichiers, y compris les cachés et système. Si vous voulez les sauter, filtrez explicitement :

foreach (string filePath in Directory.GetFiles(sourceDir))
{
    var attr = File.GetAttributes(filePath);
    if ((attr & FileAttributes.Hidden) == FileAttributes.Hidden)
        continue; // On saute les fichiers cachés

    // Le reste du code de copie
}

Erreurs liées aux chemins trop longs

Windows limitait longtemps la longueur des chemins à environ 260 caractères. Dans les versions modernes on peut lever cette limite, mais si vous travaillez sur des systèmes anciens, les chemins longs peuvent poser problème.

Liens symboliques et "junctions"

Dans des scénarios spécifiques les répertoires peuvent contenir des liens symboliques ou des «junctions». Les méthodes de copie normales peuvent les copier comme des dossiers normaux ou les ignorer. Pour la plupart des exercices pédagogiques ce n'est pas important, mais si vous travaillez avec des répertoires système — soyez prudents.

2
Mission
C# SELF, niveau 40, leçon 2
Bloqué
Copie récursive de dossiers
Copie récursive de dossiers
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION