我想用c#将一个目录的全部内容从一个位置复制到另一个位置。
使用System似乎没有办法做到这一点。没有大量递归的IO类。
如果我们添加对Microsoft的引用,VB中有一个方法可以使用。VisualBasic:
new Microsoft.VisualBasic.Devices.Computer().
FileSystem.CopyDirectory( sourceFolder, outputFolder );
这似乎是一个相当丑陋的黑客。有没有更好的办法?
我想用c#将一个目录的全部内容从一个位置复制到另一个位置。
使用System似乎没有办法做到这一点。没有大量递归的IO类。
如果我们添加对Microsoft的引用,VB中有一个方法可以使用。VisualBasic:
new Microsoft.VisualBasic.Devices.Computer().
FileSystem.CopyDirectory( sourceFolder, outputFolder );
这似乎是一个相当丑陋的黑客。有没有更好的办法?
当前回答
你可以一直使用这个,摘自微软网站。
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);
}
}
}
其他回答
对于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));
}
}
嗯,我想我误解了这个问题,但我要冒这个险。下面这个简单的方法有什么问题?
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));
}
由于这篇文章为一个同样简单的问题提供了如此简单的答案,获得了令人印象深刻的反对票,让我补充一个解释。请在投反对票前阅读这篇文章。
首先,这段代码并不打算作为问题中代码的直接替换。这只是为了说明。
microsoft . visualbasic . devices . computer . filesystm . copydirectory执行一些附加的正确性测试(例如,源和目标是否为有效目录,源是否为目标的父目录等),这些测试在这个答案中是缺失的。该代码可能也更加优化了。
也就是说,代码运行良好。它(几乎完全相同)已经在一个成熟的软件中使用多年了。除了所有IO处理固有的变化无常(例如,如果用户在代码写入USB驱动器时手动拔出USB驱动器会发生什么?),没有已知的问题。
特别地,我想指出这里使用递归绝对不是问题。无论是在理论上(概念上,这是最优雅的解决方案)还是在实践中:这段代码都不会溢出堆栈。这个堆栈足够大,甚至可以处理嵌套很深的文件层次结构。早在堆栈空间成为问题之前,文件夹路径长度限制就开始生效了。
请注意,恶意用户可能会通过使用每个字母嵌套很深的目录来打破这一假设。我还没试过。但是为了说明这一点:为了使这段代码在典型的计算机上溢出,目录必须嵌套几千次。这是不现实的情况。
容易得多
private static void CopyFilesRecursively(string sourcePath, string targetPath)
{
//Now Create all of the directories
foreach (string dirPath in Directory.GetDirectories(sourcePath, "*", SearchOption.AllDirectories))
{
Directory.CreateDirectory(dirPath.Replace(sourcePath, targetPath));
}
//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, targetPath), true);
}
}
使用这个类。
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);
}
}
public static class Extensions
{
public static void Copy(this DirectoryInfo self, DirectoryInfo destination, bool recursively)
{
foreach (var file in self.GetFiles())
{
file.CopyTo(Path.Combine(destination.FullName, file.Name));
}
if (recursively)
{
foreach (var directory in self.GetDirectories())
{
directory.Copy(destination.CreateSubdirectory(directory.Name), recursively);
}
}
}
}
使用示例:
var sourceDirectory = new DirectoryInfo(@"C:\source");
var destinationDirectory = new DirectoryInfo(@"C:\destination");
if (destinationDirectory.Exists == false)
{
sourceDirectory.Copy(destinationDirectory, recursively: true);
}