0

我正在尝试此功能,它将文件夹中的所有文件以及带有文件的相关子文件夹复制到另一个位置:

using System.IO;

 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 || drs.Substring(drs.Length-8) == "archive")
                            ret = false;
                    }
                }
                else
                {
                    ret = false;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("{0} {1} {2}", e.Message, Environment.NewLine + Environment.NewLine, e.StackTrace);
                ret = false;
            }
            return ret;
        }

在您必须将文件夹复制到另一个位置之前,它工作得很好,但是当您必须自己创建一个文件夹时(在我的示例中,我正在做一个名为“归档”的子文件夹来跟踪最后一个文件夹文件的更改)它去在无限循环中,因为它不断在 Directory.GetDirectories foreach 循环中重新扫描自身,找到新创建的子文件夹并一遍又一遍地嵌套相同的子文件夹,直到它达到“路径名太长,最大 260 个字符限制异常”。

我试图通过使用条件来避免它

|| drs.Substring(drs.Length-8) == "存档")

这应该检查目录名称,但它似乎不起作用。

我认为不同的解决方案,例如放置最大子文件夹深度扫描(IE 最大 2 个子文件夹),因此它不会继续重新扫描所有嵌套文件夹,但我在 Directory 对象中找不到这样的属性。

我无法将整个内容复制到临时文件夹,然后再复制到真实文件夹,因为下次我扫描它时,它也会重新扫描存档文件夹。

我坚持将所有目录列表放在目录对象的 ArrayList 中,所以也许我可以检查 DirName 之类的东西,但我不知道这样的属性是否存在。

有什么解决办法吗?

4

1 回答 1

0

这是递归实际上不起作用的情况,因为目录和文件的列表总是在您复制时发生变化。更好的解决方案是提前获取所有文件和文件夹的列表。

您可以使用Directory.GetFiles(String,String,SearchOption)Directory.GetDirectories(String,String,SearchOption)将 SearchOption 设置为SearchOption.AllDirectories来获取树中的所有文件和目录。这些将分别返回所有文件和所有目录。

您可以按照以下步骤复制文件:

  1. 获取所有源目录的列表并按升序排序。这将确保父目录出现在其子目录之前。
  2. 通过按排序顺序创建子目录来创建目标目录结构。您不会遇到任何路径冲突,因为排序顺序可确保您始终在子文件夹之前创建父文件夹
  3. 像以前一样将所有源文件复制到目标目录。此时顺序并不重要,因为目标目录结构已经存在。

一个简单的例子:

    static void Main(string[] args)
    {
        var sourcePath = @"c:\MyRoot\TestFolder\";

        var targetPath = @"c:\MyRoot\TestFolder\Archive\";

        var directories=Directory.GetDirectories(sourcePath, "*", SearchOption.AllDirectories);
        var files = Directory.GetFiles(sourcePath, "*", SearchOption.AllDirectories);

        if(!Directory.Exists(targetPath))
            Directory.CreateDirectory(targetPath);

        foreach (var directory in directories)
        {
            var relativePath = GetRelativePath(sourcePath, directory);
            var toPath = Path.Combine(targetPath, relativePath);
            if (!Directory.Exists(toPath))
            {
                Directory.CreateDirectory(toPath);
            }
        }

        foreach (var file in files)
        {
            var relativePath = GetRelativePath(sourcePath, file);
            var toPath = Path.Combine(targetPath, relativePath);
            if (!File.Exists(toPath))
                File.Copy(file,toPath);
        }
    }

    //This is a very quick and dirty way to get the relative path, only for demo purposes etc
    private static string GetRelativePath(string rootPath, string fullPath)
    {
        return Path.GetFullPath(fullPath).Substring(rootPath.Length);
    }
于 2013-07-25T09:01:59.310 回答