【问题标题】:Copy files from directory recursively smallest first从目录中递归地复制文件,首先是最小的
【发布时间】:2016-09-24 15:53:55
【问题描述】:

我想使用 Visual C# .NET 3.5 版将目录中的所有文件复制到目标文件夹,这很容易完成(取自 this 答案):

private static void Copy(string sourceDir, string targetDir)
{
    Directory.CreateDirectory(targetDir);

    foreach (var file in Directory.GetFiles(sourceDir))
        File.Copy(file, Path.Combine(targetDir, Path.GetFileName(file)));

    foreach (var directory in Directory.GetDirectories(sourceDir))
        Copy(directory, Path.Combine(targetDir, Path.GetFileName(directory)));
}

现在,这里有一个小问题:我希望它首先对所有文件进行最小排序,所以如果源路径是可移动驱动器,一段时间后被拔掉,它仍然会复制大部分可能的数据。使用上面的算法,如果它首先获取一个包含大文件的目录,然后继续一个包含许多小文件的目录,则用户可能会在软件仍在复制大文件时将其驱动器拔出,并且什么都不会留下驱动器上除了不完整的大文件。

我的想法是进行多个循环:首先,将每个文件路径放入一个字典中,包括其大小,然后对该字典进行排序,然后将每个文件从源复制到目标(包括创建文件夹)。

恐怕这不是一个很好的解决方案,因为循环两次大致相同对我来说似乎不合适。另外,我不确定我的字典是否可以存储这么多信息,如果源文件夹有太多不同的文件和子文件夹。

有没有更好的选择?

【问题讨论】:

  • 首先您需要切换到 FileInfo 类,因为这将包含有关文件大小的信息
  • 你的想法不错。继续执行它。

标签: c# algorithm sorting dictionary copy


【解决方案1】:

您可以使用更简单的方法,因为您可以在不使用递归的情况下获取目录子树中的所有文件。

问题的缺失部分是文件大小。可以使用DirectoryInfo 类和FileInfo 类获取此信息,而排序只是应用于文件序列的Linq 指令,如下例所示。

private static void Copy(string sourceDir, string targetDir)
{
    DirectoryInfo di = new DirectoryInfo(sourceDir);
    foreach (FileInfo fi in di.GetFiles("*.*", SearchOption.AllDirectories).OrderBy(d => d.Length))
    {
        string leftOver = fi.DirectoryName.Replace(sourceDir, "");
        string destFolder = Path.Combine(targetDir, leftOver);

        // Because the files are listed in order by size
        // we could copy a file deep down in the subtree before the 
        // ones at the top of the sourceDir

        // Luckily CreateDirectory doesn't throw if the directory exists
        // and automatically creates all the intermediate folders required
        Directory.CreateDirectory(destFolder);

        // Just write the intended copy parameters as a proof of concept
        Console.WriteLine($"{fi.Name} with size = {fi.Length} -> Copy from {fi.DirectoryName} to {Path.Combine(destFolder, fi.Name)}");
    }
}

在此示例中,我使用 Console.WriteLine 更改了 File.Copy 方法,只是为了在不复制任何内容的情况下进行概念验证,但替换是微不足道的。

还要注意,最好使用EnumerateFiles 而不是GetFiles 作为explained in the MSDN documentation

【讨论】:

  • EnumerateFiles 在 .NET 3.5 版中不可用。抱歉,我应该将其添加到我的问题中。我现在会更新。点赞,因为它看起来是一个非常简洁的解决方案!
  • 只需将其改回 GetFiles。这不是一个停止问题,尽管有很多文件代码可能会更慢。
  • 好的,谢谢。我做到了,它就像我想要的那样工作。我什至没有想到有这么短、整洁和紧凑的算法!
【解决方案2】:

我希望这会有所帮助!

首先;从源目录中获取所有文件,递归是可选的。然后继续将所有按大小排序的文件复制到目标目录。

void CopyFiles(string sourceDir, string targetDir, bool recursive = false)
{
    foreach (var file in GetFiles(sourceDir, recursive).OrderBy(f => f.Length))
    {
        var subDir = file.DirectoryName
            .Replace(sourceDir, String.Empty)
            .TrimStart(Path.DirectorySeparatorChar);
        var fullTargetDir = Path.Combine(targetDir, subDir);

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

        file.CopyTo(Path.Combine(fullTargetDir, file.Name));
    }
}

IEnumerable<FileInfo> GetFiles(string directory, bool recursive)
{
    var files = new List<FileInfo>();

    if (recursive)
    {
        foreach (var subDirectory in Directory.GetDirectories(directory))
            files.AddRange(GetFiles(subDirectory, true));
    }

    foreach (var file in Directory.GetFiles(directory))
        files.Add(new FileInfo(file));

    return files;
}

【讨论】:

  • 这不会在目标目录中创建子文件夹。
  • 好点,我一定是误读了原来的问题。我将编辑我的答案以包括复制文件夹结构。
  • @Benni 我现在已经在我的答案中包含了复制文件夹结构。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-31
  • 1970-01-01
  • 1970-01-01
  • 2014-11-07
  • 1970-01-01
  • 2022-01-18
相关资源
最近更新 更多