使用C#复制文件夹及其所有子文件夹和文件的最佳方法是什么?

9
我需要将一个文件夹从一个驱动器复制到可移动的硬盘中。这个要复制的文件夹里面有很多子文件夹和文件。输入的内容包括源路径和目标路径。
例如:
源路径: "C:\SourceFolder"
目标路径: "E:\"
复制完成后,我应该能在我的E:驱动器上看到“SourceFolder”文件夹。
谢谢。

1
这是一个重复的问题,请参考: https://dev59.com/kHVD5IYBdhLWcg3wL4iM - Ash
另一个重复的问题:https://dev59.com/YHRB5IYBdhLWcg3wbGtB - Ash
嗯,现在人们只是从其他问题中复制,所以我投票关闭。 - Robert Harvey
7个回答

12

我想这就是它。

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

它有权限问题。你能解决吗? - Adnan Ali

8

我在Channel9上找到了这个内容。自己还没有尝试过。

public static class DirectoryInfoExtensions
{
    // Copies all files from one directory to another.
    public static void CopyTo(this DirectoryInfo source, 
            string destDirectory, bool recursive)
    {
        if (source == null)
            throw new ArgumentNullException("source");
        if (destDirectory == null)
            throw new ArgumentNullException("destDirectory");
        // If the source doesn't exist, we have to throw an exception.
        if (!source.Exists)
            throw new DirectoryNotFoundException(
                    "Source directory not found: " + source.FullName);
        // Compile the target.
        DirectoryInfo target = new DirectoryInfo(destDirectory);
        // If the target doesn't exist, we create it.
        if (!target.Exists)
            target.Create();
        // Get all files and copy them over.
        foreach (FileInfo file in source.GetFiles())
        {
            file.CopyTo(Path.Combine(target.FullName, file.Name), true);
        }
        // Return if no recursive call is required.
        if (!recursive)
            return;
        // Do the same for all sub directories.
        foreach (DirectoryInfo directory in source.GetDirectories())
        {
            CopyTo(directory, 
                Path.Combine(target.FullName, directory.Name), recursive);
        }
    }
}

使用方法如下:

var source = new DirectoryInfo(@"C:\users\chris\desktop");
source.CopyTo(@"C:\users\chris\desktop_backup", true);

3

只是提醒一下,那个页面上的代码省略了他真正需要的部分。请注意评论中的内容:“要递归地迭代当前目录下的所有子文件夹,请参阅“如何:遍历目录树”。” - egrunin

2
 private static bool CopyDirectory(string SourcePath, string DestinationPath, bool overwriteexisting)
        {
            bool ret = true;
            try
            {
                SourcePath = SourcePath.EndsWith(@"\") ? SourcePath : SourcePath + @"\";
                DestinationPath = DestinationPath.EndsWith(@"\") ? DestinationPath : DestinationPath + @"\";

                if (Directory.Exists(SourcePath))
                {
                    if (Directory.Exists(DestinationPath) == false)
                        Directory.CreateDirectory(DestinationPath);

                    foreach (string fls in Directory.GetFiles(SourcePath))
                    {
                        FileInfo flinfo = new FileInfo(fls);
                        flinfo.CopyTo(DestinationPath + flinfo.Name, overwriteexisting);
                    }
                    foreach (string drs in Directory.GetDirectories(SourcePath))
                    {
                        DirectoryInfo drinfo = new DirectoryInfo(drs);
                        if (CopyDirectory(drs, DestinationPath + drinfo.Name, overwriteexisting) == false)
                            ret = false;
                    }
                    Directory.CreateDirectory(DI_Target + "//Database");
                }
                else
                {
                    ret = false;
                }
            }
            catch (Exception ex)
            {
                ret = false;
            }
            return ret;
        }

什么是 Directory.CreateDirectory(DI_Target + "//Database");? - Liquid Core

1

针对谷歌用户:在纯Win32/C++中,使用SHCreateDirectoryEx函数。

inline void EnsureDirExists(const std::wstring& fullDirPath)
{
    HWND hwnd = NULL;
    const SECURITY_ATTRIBUTES *psa = NULL;
    int retval = SHCreateDirectoryEx(hwnd, fullDirPath.c_str(), psa);
    if (retval == ERROR_SUCCESS || retval == ERROR_FILE_EXISTS || retval == ERROR_ALREADY_EXISTS)
        return; //success

    throw boost::str(boost::wformat(L"Error accessing directory path: %1%; win32 error code: %2%") 
        % fullDirPath
        % boost::lexical_cast<std::wstring>(retval));

    //TODO *djg* must do error handling here, this can fail for permissions and that sort of thing
}

1
这个问题不是关于C#吗?我并不是在抱怨(仍然点了赞)。这个方法非常有用,只是有点脱离了上下文。 - John Demetriou

-1

以下是对这个问题的另一种看法:

System.Diagnostics.ProcessStartInfo psi =
  new System.Diagnostics.ProcessStartInfo(@"XCOPY C:\folder D:\Backup\folder /i");
psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
psi.UseShellExecute = false;
System.Diagnostics.Process copyFolders = System.Diagnostics.Process.Start(psi);
copyFolders.WaitForExit();

-1

为什么不使用类似Robocopy的工具呢?

它有一个镜像选项,可以将源目录结构完全复制到目标目录中。还有各种命令行选项。这可能会节省您在代码中复制功能的努力。


2
因为RoboCopy是一个外部应用程序。在诉诸于另一个程序来完成任务之前,最好先尝试使用本地代码进行操作(如果不太复杂的话)。 - Robert Harvey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接