Copie todo el contenido de un directorio en C #

Quiero copiar todo el contenido de un directorio de una ubicación a otra en C #.

No parece haber una manera de hacerlo utilizando clases System.IO sin mucha recursión.

Hay un método en VB que podemos usar si agregamos una referencia a Microsoft.VisualBasic :

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

Esto parece un truco bastante feo. ¿Hay una mejor manera?

Más fácil

 //Now Create all of the directories foreach (string 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 (string newPath in Directory.GetFiles(SourcePath, "*.*", SearchOption.AllDirectories)) File.Copy(newPath, newPath.Replace(SourcePath, DestinationPath), true); 

Hmm, creo que no entiendo bien la pregunta, pero me arriesgaré. ¿Qué pasa con el siguiente método directo?

 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)); } 

EDITAR Dado que este anuncio ha acumulado una impresionante cantidad de votos negativos para una respuesta tan simple a una pregunta igualmente simple, permítanme agregar una explicación. Por favor, lea esto antes de downvoting .

En primer lugar, este código no está intencionado como un reemplazo directo al código en la pregunta. Es solo para fines ilustrativos.

Microsoft.VisualBasic.Devices.Computer.FileSystem.CopyDirectory realiza algunas pruebas de corrección adicionales (por ejemplo, si el origen y el destino son directorios válidos, si el origen es un padre del destino, etc.) que faltan en esta respuesta. Ese código probablemente también esté más optimizado.

Dicho eso, el código funciona bien . Se ha utilizado (casi idénticamente) en un software maduro durante años. Además de la inconstancia inherente presente con todos los manejos de IO (por ejemplo, ¿qué sucede si el usuario desenchufa manualmente la unidad USB mientras el código está escribiendo en ella?), No hay problemas conocidos.

En particular, me gustaría señalar que el uso de la recursión aquí no es un problema en absoluto. Ni en teoría (conceptualmente, es la solución más elegante) ni en la práctica: este código no desbordará la stack . La stack es lo suficientemente grande como para manejar incluso jerarquías de archivos nesteds profundamente. Mucho antes de que el espacio de la stack se convierta en un problema, la limitación de longitud de la ruta de la carpeta entra en acción.

Tenga en cuenta que un usuario malintencionado podría romper esta suposición mediante el uso de directorios profundamente nesteds de una letra cada uno. No he intentado esto. Pero solo para ilustrar el punto: para hacer que este código se desborde en una computadora típica, los directorios tendrían que estar nesteds unas miles de veces. Esto simplemente no es un escenario realista.

Copiado desde MSDN :

 using System; using System.IO; class CopyDir { public static void Copy(string sourceDirectory, string 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() { string sourceDirectory = @"c:\sourceDirectory"; string targetDirectory = @"c:\targetDirectory"; Copy(sourceDirectory, targetDirectory); } // Output will vary based on the contents of the source directory. } 

Prueba esto:

 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(); 

Sus argumentos de xcopy pueden variar pero usted entiende la idea.

O, si quiere ir por las malas, agregue una referencia a su proyecto para Microsoft.VisualBasic y luego use lo siguiente:

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

Sin embargo, usar una de las funciones recursivas es una mejor forma de hacerlo, ya que no tendrá que cargar el dll de VB.

Este sitio siempre me ha ayudado mucho, y ahora es mi turno de ayudar a los demás con lo que sé.

Espero que mi código a continuación sea útil para alguien.

 string source_dir = @"E:\"; string destination_dir = @"C:\"; // substring is to remove destination_dir absolute path (E:\). // Create subdirectory structure in destination foreach (string dir in System.IO.Directory.GetDirectories(source_dir, "*", System.IO.SearchOption.AllDirectories)) { System.IO.Directory.CreateDirectory(System.IO.Path.Combine(destination_dir, dir.Substring(source_dir.Length))); // Example: // > C:\sources (and not C:\E:\sources) } foreach (string 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.Substring(source_dir.Length))); } 

Copie la carpeta recursivamente sin recursión para evitar el desbordamiento de la stack.

 public static void CopyDirectory(string source, string 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 string Source { get; private set; } public string Target { get; private set; } public Folders(string source, string target) { Source = source; Target = target; } } 

Aquí hay una clase de utilidad que he usado para tareas IO como esta.

 using System; using System.Runtime.InteropServices; namespace MyNameSpace { public class ShellFileOperation { private static String StringArrayToMultiString(String[] stringArray) { String multiString = ""; if (stringArray == null) return ""; for (int i=0 ; i 

Una pequeña mejora en la respuesta de d4nt, ya que es probable que desee verificar errores y no tener que cambiar las rutas de xcopy si está trabajando en un servidor y máquina de desarrollo:

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

Si le gusta la respuesta popular de Konrad, pero desea que la source sí misma sea una carpeta bajo el target , en lugar de poner sus hijos debajo de la carpeta de target , aquí está el código para eso. Devuelve el DirectoryInfo recién creado, que es útil:

 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; } 

Siempre puedes usar esto , tomado del sitio web de Microsofts.

 static void Main() { // Copy from the current directory, include subdirectories. DirectoryCopy(".", @".\temp", true); } private static void DirectoryCopy(string sourceDirName, string 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) { string 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) { string temppath = Path.Combine(destDirName, subdir.Name); DirectoryCopy(subdir.FullName, temppath, copySubDirs); } } } 

tboswell’s replace Proof version (que es resistente al patrón repetitivo en filepath)

 public static void copyAll(string SourcePath , string DestinationPath ) { //Now Create all of the directories foreach (string 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 (string newPath in Directory.GetFiles(SourcePath, "*.*", SearchOption.AllDirectories)) File.Copy(newPath, Path.Combine(DestinationPath , newPath.Remove(0, SourcePath.Length)) , true); } 

Puede que no sea consciente del rendimiento, pero lo estoy usando para carpetas de 30MB y funciona sin problemas. Además, no me gustó toda la cantidad de código y recursividad necesarios para una tarea tan fácil.

 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); 

Nota: ZipFile está disponible en .NET 4.5+ en el espacio de nombres System.IO.Compression

Perdón por el código anterior, todavía tenía errores 🙁 (presa del problema de arma más rápido). Aquí está probado y funciona. La clave es SearchOption.AllDirectories, que elimina la necesidad de recursión explícita.

 string path = "C:\\a"; string[] dirs = Directory.GetDirectories(path, "*.*", SearchOption.AllDirectories); string 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); } } 

Este es mi código espero que esta ayuda

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

Aquí hay un método de extensión para DirectoryInfo a la FileInfo.CopyTo (tenga en cuenta el parámetro de overwrite ):

 public static DirectoryInfo CopyTo(this DirectoryInfo sourceDir, string 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; } 

Mejor que cualquier código (método de extensión para DirectoryInfo con recursión)

 public static bool CopyTo(this DirectoryInfo source, string destination) { try { foreach (string 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 (string filePath in Directory.GetFiles(source.FullName)) { File.Copy(filePath, filePath.Replace(source.FullName,destination), true); } return true; } catch (IOException exp) { return false; } } 

Usa esta clase

 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, string target, bool overwiteFiles = true) { CopyTo(source, new DirectoryInfo(target), overwiteFiles); } } 

Una variante con un solo bucle para copiar todas las carpetas y archivos:

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