Copiez tout le contenu d’un répertoire en C #

Je souhaite copier l’intégralité du contenu d’un répertoire d’un emplacement à un autre en C #.

Il ne semble pas y avoir de moyen de le faire en utilisant les classes System.IO sans beaucoup de récursivité.

Il existe une méthode dans VB que nous pouvons utiliser si nous ajoutons une référence à Microsoft.VisualBasic :

 new Microsoft.VisualBasic.Devices.Computer(). FileSystem.CopyDirectory( sourceFolder, outputFolder ); 

Cela semble être un hack plutôt moche. Y a-t-il une meilleure façon?

Beaucoup plus facile

 //Now Create all of the directories foreach (ssortingng dirPath in Directory.GetDirectories(SourcePath, "*", SearchOption.AllDirectories)) Directory.CreateDirectory(dirPath.Replace(SourcePath, DestinationPath)); //Copy all the files & Replaces any files with the same name foreach (ssortingng newPath in Directory.GetFiles(SourcePath, "*.*", SearchOption.AllDirectories)) File.Copy(newPath, newPath.Replace(SourcePath, DestinationPath), true); 

Hmm, je pense que je comprends mal la question mais je vais risquer ça. Quel est le problème avec la méthode simple suivante?

 public static void CopyFilesRecursively(DirectoryInfo source, DirectoryInfo target) { foreach (DirectoryInfo dir in source.GetDirectories()) CopyFilesRecursively(dir, target.CreateSubdirectory(dir.Name)); foreach (FileInfo file in source.GetFiles()) file.CopyTo(Path.Combine(target.FullName, file.Name)); } 

EDIT Étant donné que cette publication a recueilli un nombre impressionnant d’atouts pour une réponse aussi simple à une question tout aussi simple, permettez-moi d’append une explication. Veuillez lire ceci avant de voter .

Tout d’abord, ce code n’est pas destiné à remplacer le code dans la question. C’est uniquement à titre d’illustration.

Microsoft.VisualBasic.Devices.Computer.FileSystem.CopyDirectory effectue des tests de correction supplémentaires (par exemple, si la source et la cible sont des répertoires valides, si la source est un parent de la cible, etc.) qui ne figurent pas dans cette réponse. Ce code est probablement aussi plus optimisé.

Cela dit, le code fonctionne bien . Il a été (presque identique) utilisé dans un logiciel mature depuis des années. Mis à part le manque de souplesse inhérent à toutes les manipulations IO (par exemple, que se passe-t-il si l’utilisateur détwig manuellement le lecteur USB pendant que votre code lui écrit?), Il n’y a aucun problème connu.

En particulier, je voudrais souligner que l’utilisation de la récursivité ici n’est absolument pas un problème. Ni en théorie (conceptuellement, c’est la solution la plus élégante) ni en pratique: ce code ne débordera pas la stack . La stack est suffisamment grande pour gérer même les hiérarchies de fichiers profondément nestedes. Bien avant que l’espace de la stack ne devienne un problème, la limitation de la longueur du chemin du dossier se déclenche.

Notez qu’un utilisateur malveillant peut être en mesure de casser cette hypothèse en utilisant des répertoires nesteds d’une lettre chacun. Je n’ai pas essayé ça. Mais pour illustrer ce point: pour que ce code déborde sur un ordinateur typique, les répertoires doivent être nesteds plusieurs milliers de fois. Ce n’est tout simplement pas un scénario réaliste.

Copié à partir de MSDN :

 using System; using System.IO; class CopyDir { public static void Copy(ssortingng sourceDirectory, ssortingng targetDirectory) { DirectoryInfo diSource = new DirectoryInfo(sourceDirectory); DirectoryInfo diTarget = new DirectoryInfo(targetDirectory); CopyAll(diSource, diTarget); } public static void CopyAll(DirectoryInfo source, DirectoryInfo target) { Directory.CreateDirectory(target.FullName); // Copy each file into the new directory. foreach (FileInfo fi in source.GetFiles()) { Console.WriteLine(@"Copying {0}\{1}", target.FullName, fi.Name); fi.CopyTo(Path.Combine(target.FullName, fi.Name), true); } // Copy each subdirectory using recursion. foreach (DirectoryInfo diSourceSubDir in source.GetDirectories()) { DirectoryInfo nextTargetSubDir = target.CreateSubdirectory(diSourceSubDir.Name); CopyAll(diSourceSubDir, nextTargetSubDir); } } public static void Main() { ssortingng sourceDirectory = @"c:\sourceDirectory"; ssortingng targetDirectory = @"c:\targetDirectory"; Copy(sourceDirectory, targetDirectory); } // Output will vary based on the contents of the source directory. } 

Essaye ça:

 Process proc = new Process(); proc.StartInfo.UseShellExecute = true; proc.StartInfo.FileName = Path.Combine(Environment.SystemDirectory, "xcopy.exe"); proc.StartInfo.Arguments = @"C:\source C:\destination /E /I"; proc.Start(); 

Vos arguments xcopy peuvent varier, mais vous obtenez l’idée.

Ou, si vous voulez faire le difficile, ajoutez une référence à votre projet pour Microsoft.VisualBasic, puis utilisez les éléments suivants:

 Microsoft.VisualBasic.FileIO.FileSystem.CopyDirectory(fromDirectory, toDirectory); 

Cependant, l’utilisation d’une des fonctions récursives est une meilleure solution car elle n’a pas besoin de charger la DLL VB.

Ce site m’a toujours beaucoup aidé et maintenant c’est à mon tour d’aider les autres avec ce que je sais.

J’espère que mon code ci-dessous sera utile pour quelqu’un.

 ssortingng source_dir = @"E:\"; ssortingng destination_dir = @"C:\"; // subssortingng is to remove destination_dir absolute path (E:\). // Create subdirectory structure in destination foreach (ssortingng dir in System.IO.Directory.GetDirectories(source_dir, "*", System.IO.SearchOption.AllDirectories)) { System.IO.Directory.CreateDirectory(System.IO.Path.Combine(destination_dir, dir.Subssortingng(source_dir.Length))); // Example: // > C:\sources (and not C:\E:\sources) } foreach (ssortingng file_name in System.IO.Directory.GetFiles(source_dir, "*", System.IO.SearchOption.AllDirectories)) { System.IO.File.Copy(file_name, System.IO.Path.Combine(destination_dir, file_name.Subssortingng(source_dir.Length))); } 

Copiez le dossier de manière récursive sans récursivité pour éviter le débordement de la stack.

 public static void CopyDirectory(ssortingng source, ssortingng target) { var stack = new Stack(); stack.Push(new Folders(source, target)); while (stack.Count > 0) { var folders = stack.Pop(); Directory.CreateDirectory(folders.Target); foreach (var file in Directory.GetFiles(folders.Source, "*.*")) { File.Copy(file, Path.Combine(folders.Target, Path.GetFileName(file))); } foreach (var folder in Directory.GetDirectories(folders.Source)) { stack.Push(new Folders(folder, Path.Combine(folders.Target, Path.GetFileName(folder)))); } } } public class Folders { public ssortingng Source { get; private set; } public ssortingng Target { get; private set; } public Folders(ssortingng source, ssortingng target) { Source = source; Target = target; } } 

Voici une classe d’utilitaire que j’ai utilisée pour des tâches IO comme celle-ci.

 using System; using System.Runtime.InteropServices; namespace MyNameSpace { public class ShellFileOperation { private static Ssortingng SsortingngArrayToMultiSsortingng(Ssortingng[] ssortingngArray) { Ssortingng multiSsortingng = ""; if (ssortingngArray == null) return ""; for (int i=0 ; i 

Une amélioration mineure de la réponse de d4nt, car vous souhaiterez probablement vérifier les erreurs et ne pas avoir à modifier les chemins xcopy si vous travaillez sur un serveur et une machine de développement:

 public void CopyFolder(ssortingng source, ssortingng destination) { ssortingng xcopyPath = Environment.GetEnvironmentVariable("WINDIR") + @"\System32\xcopy.exe"; ProcessStartInfo info = new ProcessStartInfo(xcopyPath); info.UseShellExecute = false; info.RedirectStandardOutput = true; info.Arguments = ssortingng.Format("\"{0}\" \"{1}\" /E /I", source, destination); Process process = Process.Start(info); process.WaitForExit(); ssortingng result = process.StandardOutput.ReadToEnd(); if (process.ExitCode != 0) { // Or your own custom exception, or just return false if you prefer. throw new InvalidOperationException(ssortingng.Format("Failed to copy {0} to {1}: {2}", source, destination, result)); } } 

Si vous aimez la réponse populaire de Konrad, mais que vous voulez que la source soit un dossier sous la target , plutôt que de placer ses enfants dans le dossier target , voici le code pour cela. Il renvoie le nouveau DirectoryInfo , ce qui est pratique:

 public static DirectoryInfo CopyFilesRecursively(DirectoryInfo source, DirectoryInfo target) { var newDirectoryInfo = target.CreateSubdirectory(source.Name); foreach (var fileInfo in source.GetFiles()) fileInfo.CopyTo(Path.Combine(newDirectoryInfo.FullName, fileInfo.Name)); foreach (var childDirectoryInfo in source.GetDirectories()) CopyFilesRecursively(childDirectoryInfo, newDirectoryInfo); return newDirectoryInfo; } 

Vous pouvez toujours utiliser ceci , extrait du site Web de Microsofts.

 static void Main() { // Copy from the current directory, include subdirectories. DirectoryCopy(".", @".\temp", true); } private static void DirectoryCopy(ssortingng sourceDirName, ssortingng destDirName, bool copySubDirs) { // Get the subdirectories for the specified directory. DirectoryInfo dir = new DirectoryInfo(sourceDirName); if (!dir.Exists) { throw new DirectoryNotFoundException( "Source directory does not exist or could not be found: " + sourceDirName); } DirectoryInfo[] dirs = dir.GetDirectories(); // If the destination directory doesn't exist, create it. if (!Directory.Exists(destDirName)) { Directory.CreateDirectory(destDirName); } // Get the files in the directory and copy them to the new location. FileInfo[] files = dir.GetFiles(); foreach (FileInfo file in files) { ssortingng temppath = Path.Combine(destDirName, file.Name); file.CopyTo(temppath, false); } // If copying subdirectories, copy them and their contents to new location. if (copySubDirs) { foreach (DirectoryInfo subdir in dirs) { ssortingng temppath = Path.Combine(destDirName, subdir.Name); DirectoryCopy(subdir.FullName, temppath, copySubDirs); } } } 

tboswell remplace la version de preuve (qui résiste au motif répété dans le chemin de fichier)

 public static void copyAll(ssortingng SourcePath , ssortingng DestinationPath ) { //Now Create all of the directories foreach (ssortingng dirPath in Directory.GetDirectories(SourcePath, "*", SearchOption.AllDirectories)) Directory.CreateDirectory(Path.Combine(DestinationPath ,dirPath.Remove(0, SourcePath.Length )) ); //Copy all the files & Replaces any files with the same name foreach (ssortingng newPath in Directory.GetFiles(SourcePath, "*.*", SearchOption.AllDirectories)) File.Copy(newPath, Path.Combine(DestinationPath , newPath.Remove(0, SourcePath.Length)) , true); } 

Il peut ne pas être compatible avec les performances, mais je l’utilise pour les dossiers de 30 Mo et cela fonctionne parfaitement. De plus, je n’ai pas aimé toute la quantité de code et de récursivité requirejse pour une tâche aussi facile.

 var source_folder = "c:\src"; var dest_folder = "c:\dest"; var zipFile = source_folder + ".zip"; ZipFile.CreateFromDirectory(source_folder, zipFile); ZipFile.ExtractToDirectory(zipFile, dest_folder); File.Delete(zipFile); 

Remarque: ZipFile est disponible sur .NET 4.5+ dans l’espace de noms System.IO.Compression

Désolé pour le code précédent, il y avait toujours des bugs 🙁 (en proie au problème de pistolet le plus rapide). Ici, il est testé et fonctionne. La clé est la SearchOption.AllDirectories, ce qui élimine le besoin de récursion explicite.

 ssortingng path = "C:\\a"; ssortingng[] dirs = Directory.GetDirectories(path, "*.*", SearchOption.AllDirectories); ssortingng newpath = "C:\\x"; try { Directory.CreateDirectory(newpath); } catch (IOException ex) { Console.WriteLine(ex.Message); } for (int j = 0; j < dirs.Length; j++) { try { Directory.CreateDirectory(dirs[j].Replace(path, newpath)); } catch (IOException ex) { Console.WriteLine(ex.Message); } } string[] files = Directory.GetFiles(path, "*.*", SearchOption.AllDirectories); for (int j = 0; j < files.Length; j++) { try { File.Copy(files[j], files[j].Replace(path, newpath)); } catch (IOException ex) { Console.WriteLine(ex.Message); } } 

Ceci est mon code espérons que cette aide

  private void KCOPY(ssortingng source, ssortingng destination) { if (IsFile(source)) { ssortingng target = Path.Combine(destination, Path.GetFileName(source)); File.Copy(source, target, true); } else { ssortingng fileName = Path.GetFileName(source); ssortingng target = System.IO.Path.Combine(destination, fileName); if (!System.IO.Directory.Exists(target)) { System.IO.Directory.CreateDirectory(target); } List files = GetAllFileAndFolder(source); foreach (ssortingng file in files) { KCOPY(file, target); } } } private List GetAllFileAndFolder(ssortingng path) { List allFile = new List(); foreach (ssortingng dir in Directory.GetDirectories(path)) { allFile.Add(dir); } foreach (ssortingng file in Directory.GetFiles(path)) { allFile.Add(file); } return allFile; } private bool IsFile(ssortingng path) { if ((File.GetAtsortingbutes(path) & FileAtsortingbutes.Directory) == FileAtsortingbutes.Directory) { return false; } return true; } 

Voici une méthode d’extension pour DirectoryInfo à la FileInfo.CopyTo (notez le paramètre d’ overwrite ):

 public static DirectoryInfo CopyTo(this DirectoryInfo sourceDir, ssortingng destinationPath, bool overwrite = false) { var sourcePath = sourceDir.FullName; var destination = new DirectoryInfo(destinationPath); destination.Create(); foreach (var sourceSubDirPath in Directory.EnumerateDirectories(sourcePath, "*", SearchOption.AllDirectories)) Directory.CreateDirectory(sourceSubDirPath.Replace(sourcePath, destinationPath)); foreach (var file in Directory.EnumerateFiles(sourcePath, "*", SearchOption.AllDirectories)) File.Copy(file, file.Replace(sourcePath, destinationPath), overwrite); return destination; } 

Mieux que n’importe quel code (méthode d’extension à DirectoryInfo avec récursivité)

 public static bool CopyTo(this DirectoryInfo source, ssortingng destination) { try { foreach (ssortingng dirPath in Directory.GetDirectories(source.FullName)) { var newDirPath = dirPath.Replace(source.FullName, destination); Directory.CreateDirectory(newDirPath); new DirectoryInfo(dirPath).CopyTo(newDirPath); } //Copy all the files & Replaces any files with the same name foreach (ssortingng filePath in Directory.GetFiles(source.FullName)) { File.Copy(filePath, filePath.Replace(source.FullName,destination), true); } return true; } catch (IOException exp) { return false; } } 

Utilisez cette classe.

 public static class Extensions { public static void CopyTo(this DirectoryInfo source, DirectoryInfo target, bool overwiteFiles = true) { if (!source.Exists) return; if (!target.Exists) target.Create(); Parallel.ForEach(source.GetDirectories(), (sourceChildDirectory) => CopyTo(sourceChildDirectory, new DirectoryInfo(Path.Combine(target.FullName, sourceChildDirectory.Name)))); foreach (var sourceFile in source.GetFiles()) sourceFile.CopyTo(Path.Combine(target.FullName, sourceFile.Name), overwiteFiles); } public static void CopyTo(this DirectoryInfo source, ssortingng target, bool overwiteFiles = true) { CopyTo(source, new DirectoryInfo(target), overwiteFiles); } } 

Une variante avec une seule boucle pour copier tous les dossiers et fichiers:

 foreach (var f in Directory.GetFileSystemEnsortinges(path, "*", SearchOption.AllDirectories)) { var output = Regex.Replace(f, @"^" + path, newPath); if (File.Exists(f)) File.Copy(f, output, true); else Directory.CreateDirectory(output); }