简体   繁体   English

从目录递归最小复制文件

[英]Copy files from directory recursively smallest first

I want to copy all files in a directory to a destination folder using Visual C# .NET version 3.5, which can be done pretty easily (taken from this answer): 我想所有目录中的文件复制到使用Visual C#.NET版本3.5中的目标文件夹,它可以很容易地完成(取自答案):

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)));
}

Now, there's one little problem here: I want it to sort all files smallest first, so if the source path is a removable drive, which gets plugged out after some time, it would still have most possible data copied. 现在,这里有一个小问题:我希望它首先对所有文件进行最小排序,因此,如果源路径是可移动驱动器,一段时间后将其拔出,则仍将复制大多数数据。 With upper algorithm, if it takes a directory containing big files first and continues with a directory containing many smaller ones afterwards, there is the chance that the user will plug his drive out while the software is still copying the big file, and nothing will stay on the drive except the incomplete big file. 使用高级算法时,如果先获取包含大文件的目录,然后再包含包含许多小文件的目录,则用户有可能在软件仍在复制大文件时将驱动器拔出,而不会留下任何东西在驱动器上,但不完整的大文件除外。

My idea was to do multiple loops: First, every filepath would be put in a dictionary including its size, then this dictionary would get sorted, and then every file would be copied from source to destination (including folder creation). 我的想法是做多个循环:首先,将每个文件路径放入包含其大小的字典中,然后对该字典进行排序,然后将每个文件从源复制到目标(包括创建文件夹)。

I'm afraid this is not a very neat solution, since looping two times about the same just doesn't seem right to me. 恐怕这不是一个很整洁的解决方案,因为对我来说,两次循环差不多是不合适的。 Also, I'm not sure if my dictionary can store that much information, if the source folder has got too many different files and subfolders. 另外,如果源文件夹中包含太多不同的文件和子文件夹,我不确定我的词典是否可以存储那么多信息。

Are there any better options to choose from? 有什么更好的选择吗?

You could use a simpler method based on the fact that you can get all the files in a directory subtree just asking for them without using recursion. 您可以基于以下事实使用更简单的方法:您可以在目录子树中获取所有文件,而无需使用递归即可。

The missing piece of the problem is the file size. 问题的缺失部分是文件大小。 This information could be obtained using the DirectoryInfo class and the FileInfo class while the ordering is just a Linq instruction applied to the sequence of files as in the following example. 可以使用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)}");
    }
}

In this example I have changed the File.Copy method with a Console.WriteLine just to have a proof of concept without copying anything, but the substitution is trivial. 在此示例中,我已使用Console.WriteLine更改了File.Copy方法,只是为了获得概念证明而无需复制任何内容,但是替换很简单。

Notice also that it is better to use EnumerateFiles instead of GetFiles as explained in the MSDN documentation 还要注意,最好使用EnumerateFiles代替GetFilesMSDN文档中所述

I hope this helps! 我希望这有帮助!

First; 第一; get all files from the source directory, with recursion being optional. 从源目录获取所有文件,递归是可选的。 Then proceed to copy all files ordered by size to the target directory. 然后继续将按大小排序的所有文件复制到目标目录。

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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM