在C#中复制一个目录的全部内容
我想在C#中将目录的全部内容从一个位置复制到另一个位置。
似乎没有办法做到这一点使用System.IO
类没有很多递归。
在VB中有一个方法,如果我们添加一个对Microsoft.VisualBasic
的引用,就可以使用它:
new Microsoft.VisualBasic.Devices.Computer(). FileSystem.CopyDirectory( sourceFolder, outputFolder );
这似乎是一个相当丑陋的黑客。 有没有更好的办法?
更容易
//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);
嗯,我想我误解了这个问题,但我会冒这个险。 以下简单的方法有什么问题?
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)); }
编辑由于这个帖子已经获得了令人印象深刻的数量downvotes这样一个简单的答案一个同样简单的问题,让我添加一个解释。 在投票前 请 阅读 。
首先, 这个代码并不是对问题中的代码的简单替换 。 这只是为了说明的目的。
Microsoft.VisualBasic.Devices.Computer.FileSystem.CopyDirectory
执行一些额外的正确性测试(例如源和目标是否是有效的目录,源是否是目标的父级等)。 该代码可能也更加优化。
也就是说,代码运行良好 。 它已经 (几乎完全相同)在一个成熟的软件中使用多年。 除了所有的IO处理(例如,如果用户在您的代码写入时手动拔下USB驱动器会发生什么情况,会出现什么情况),固有的浮躁现象还没有已知的问题。
特别是,我想指出,这里使用递归是绝对不是问题。 理论上(概念上讲,这是最优雅的解决方案),也不是在实践中: 这个代码不会溢出堆栈 。 该堆栈足够大,可以处理甚至是深度嵌套的文件层次结构。 在堆栈空间成为问题之前很久,文件夹路径长度限制就会启动。
请注意, 恶意用户可能能够通过使用每个深度嵌套的一个字母的目录来打破这一假设。 我没有试过这个。 但是仅仅为了说明这一点:为了使这个代码在一个典型的计算机上溢出,这些目录将不得不嵌套几千次。 这根本不是一个现实的情况。
从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. }
尝试这个:
Process proc = new Process(); proc.StartInfo.UseShellExecute = true; proc.StartInfo.FileName = @"C:\WINDOWS\system32\xcopy.exe"; proc.StartInfo.Arguments = @"C:\source C:\destination /E /I"; proc.Start();
你的xcopy参数可能会有所不同,但你明白了。
或者,如果您想要坚持下去,请为您的Microsoft.VisualBasic项目添加一个引用,然后使用以下命令:
Microsoft.VisualBasic.FileIO.FileSystem.CopyDirectory(fromDirectory, toDirectory);
但是,使用其中一个递归函数是一个更好的方法,因为它不需要加载VB DLL。
这个网站总是帮助我很多,现在是我用我所知道的帮助别人的时候了。
我等待下面的代码对某人有用。
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(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, destination_dir + file_name.Substring(source_dir.Length)); }
递归地复制文件夹而无需递归以避免堆栈溢出。
public static void CopyDirectory(string source, string target) { var stack = new Stack<Folders>(); 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; } }
这里有一个我用于IO任务的实用工具类。
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<stringArray.Length ; i++) multiString += stringArray[i] + '\0'; multiString += '\0'; return multiString; } public static bool Copy(string source, string dest) { return Copy(new String[] { source }, new String[] { dest }); } public static bool Copy(String[] source, String[] dest) { Win32.SHFILEOPSTRUCT FileOpStruct = new Win32.SHFILEOPSTRUCT(); FileOpStruct.hwnd = IntPtr.Zero; FileOpStruct.wFunc = (uint)Win32.FO_COPY; String multiSource = StringArrayToMultiString(source); String multiDest = StringArrayToMultiString(dest); FileOpStruct.pFrom = Marshal.StringToHGlobalUni(multiSource); FileOpStruct.pTo = Marshal.StringToHGlobalUni(multiDest); FileOpStruct.fFlags = (ushort)Win32.ShellFileOperationFlags.FOF_NOCONFIRMATION; FileOpStruct.lpszProgressTitle = ""; FileOpStruct.fAnyOperationsAborted = 0; FileOpStruct.hNameMappings = IntPtr.Zero; int retval = Win32.SHFileOperation(ref FileOpStruct); if(retval != 0) return false; return true; } public static bool Move(string source, string dest) { return Move(new String[] { source }, new String[] { dest }); } public static bool Delete(string file) { Win32.SHFILEOPSTRUCT FileOpStruct = new Win32.SHFILEOPSTRUCT(); FileOpStruct.hwnd = IntPtr.Zero; FileOpStruct.wFunc = (uint)Win32.FO_DELETE; String multiSource = StringArrayToMultiString(new string[] { file }); FileOpStruct.pFrom = Marshal.StringToHGlobalUni(multiSource); FileOpStruct.pTo = IntPtr.Zero; FileOpStruct.fFlags = (ushort)Win32.ShellFileOperationFlags.FOF_SILENT | (ushort)Win32.ShellFileOperationFlags.FOF_NOCONFIRMATION | (ushort)Win32.ShellFileOperationFlags.FOF_NOERRORUI | (ushort)Win32.ShellFileOperationFlags.FOF_NOCONFIRMMKDIR; FileOpStruct.lpszProgressTitle = ""; FileOpStruct.fAnyOperationsAborted = 0; FileOpStruct.hNameMappings = IntPtr.Zero; int retval = Win32.SHFileOperation(ref FileOpStruct); if(retval != 0) return false; return true; } public static bool Move(String[] source, String[] dest) { Win32.SHFILEOPSTRUCT FileOpStruct = new Win32.SHFILEOPSTRUCT(); FileOpStruct.hwnd = IntPtr.Zero; FileOpStruct.wFunc = (uint)Win32.FO_MOVE; String multiSource = StringArrayToMultiString(source); String multiDest = StringArrayToMultiString(dest); FileOpStruct.pFrom = Marshal.StringToHGlobalUni(multiSource); FileOpStruct.pTo = Marshal.StringToHGlobalUni(multiDest); FileOpStruct.fFlags = (ushort)Win32.ShellFileOperationFlags.FOF_NOCONFIRMATION; FileOpStruct.lpszProgressTitle = ""; FileOpStruct.fAnyOperationsAborted = 0; FileOpStruct.hNameMappings = IntPtr.Zero; int retval = Win32.SHFileOperation(ref FileOpStruct); if(retval != 0) return false; return true; } } }
如果你喜欢Konrad的流行答案,但是你希望source
本身是target
文件夹下的文件夹,而不是把它的子目录放在target
文件夹下,那么这里就是代码。 它返回新创建的DirectoryInfo
,这是很方便的:
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; }
tboswell替换了Proof版本(这对于在文件路径中重复模式是有弹性的)
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); }
对不起,以前的代码,它仍然有错误:(陷入猎枪最快的枪问题)。在这里它被测试和工作。关键是SearchOption.AllDirectories,这消除了显式递归的需要。
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); } }
对d4nt的答案稍作改进,因为如果您在服务器和开发计算机上工作,您可能需要检查错误并且不必更改xcopy路径:
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)); } }
这是我的代码希望这个帮助
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<string> files = GetAllFileAndFolder(source); foreach (string file in files) { KCOPY(file, target); } } } private List<string> GetAllFileAndFolder(string path) { List<string> allFile = new List<string>(); 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; }
这里是DirectoryInfo的一个扩展方法FileInfo.CopyTo (注意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; }
你可以随时使用这个 ,从微软网站。
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); } } }
使用这个类。
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(); foreach (var sourceChildDirectory in source.GetDirectories()) 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); } }
优于任何代码(使用递归方式向DirectoryInfo的扩展方法)
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; } }