我想用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 );
这似乎是一个相当丑陋的黑客。有没有更好的办法?
当前回答
嗯,我想我误解了这个问题,但我要冒这个险。下面这个简单的方法有什么问题?
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驱动器会发生什么?),没有已知的问题。
特别地,我想指出这里使用递归绝对不是问题。无论是在理论上(概念上,这是最优雅的解决方案)还是在实践中:这段代码都不会溢出堆栈。这个堆栈足够大,甚至可以处理嵌套很深的文件层次结构。早在堆栈空间成为问题之前,文件夹路径长度限制就开始生效了。
请注意,恶意用户可能会通过使用每个字母嵌套很深的目录来打破这一假设。我还没试过。但是为了说明这一点:为了使这段代码在典型的计算机上溢出,目录必须嵌套几千次。这是不现实的情况。
其他回答
tboswell的替换证明版本(这是弹性的重复模式在文件路径)
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);
}
如果您喜欢Konrad的流行答案,但希望源代码本身是目标文件夹下的一个文件夹,而不是将它的子文件夹放在目标文件夹下,下面是实现该目的的代码。它返回新创建的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;
}
递归复制文件夹而不递归,以避免堆栈溢出。
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;
}
}
下面的代码是微软建议如何复制目录 由亲爱的@iato分享 但是它只是递归地复制源文件夹的子目录和文件,而不复制源文件夹本身(如右键单击->复制)。
但在这个答案下面有一个棘手的方法:
private static void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs = true)
{
// 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);
}
}
}
如果你想递归复制源文件夹和子文件夹的内容,你可以像这样简单地使用它:
string source = @"J:\source\";
string dest= @"J:\destination\";
DirectoryCopy(source, dest);
但是如果你想复制源目录自己(类似于你右键单击源文件夹,然后单击复制,然后在目标文件夹中单击粘贴),你应该像这样使用:
string source = @"J:\source\";
string dest= @"J:\destination\";
DirectoryCopy(source, Path.Combine(dest, new DirectoryInfo(source).Name));
只是想加上我的版本。它可以处理目录和文件,如果目标文件存在,则可以覆盖或跳过。
public static void Copy(
string source,
string destination,
string pattern = "*",
bool includeSubFolders = true,
bool overwrite = true,
bool overwriteOnlyIfSourceIsNewer = false)
{
if (File.Exists(source))
{
// Source is a file, copy and leave
CopyFile(source, destination);
return;
}
if (!Directory.Exists(source))
{
throw new DirectoryNotFoundException($"Source directory does not exists: `{source}`");
}
var files = Directory.GetFiles(
source,
pattern,
includeSubFolders ?
SearchOption.AllDirectories :
SearchOption.TopDirectoryOnly);
foreach (var file in files)
{
var newFile = file.Replace(source, destination);
CopyFile(file, newFile, overwrite, overwriteOnlyIfSourceIsNewer);
}
}
private static void CopyFile(
string source,
string destination,
bool overwrite = true,
bool overwriteIfSourceIsNewer = false)
{
if (!overwrite && File.Exists(destination))
{
return;
}
if (overwriteIfSourceIsNewer && File.Exists(destination))
{
var sourceLastModified = File.GetLastWriteTimeUtc(source);
var destinationLastModified = File.GetLastWriteTimeUtc(destination);
if (sourceLastModified <= destinationLastModified)
{
return;
}
CreateDirectory(destination);
File.Copy(source, destination, overwrite);
return;
}
CreateDirectory(destination);
File.Copy(source, destination, overwrite);
}
private static void CreateDirectory(string filePath)
{
var targetDirectory = Path.GetDirectoryName(filePath);
if (targetDirectory != null && !Directory.Exists(targetDirectory))
{
Directory.CreateDirectory(targetDirectory);
}
}