首页 > 解决方案 > 关于加速硬盘备份代码的建议

问题描述

我有以下硬盘备份代码,它在复制之前比较每个文件的 .LastWriteTime() 时间,它的运行速度比我预期的要慢。我的假设是,如果没有要更新的文件,它应该运行得非常快(大约几分钟)。我发现通过 USB3.0 传输 210 GB 仍然需要一个多小时。我想知道我的代码中是否有任何不必要的、耗时的部分可以改进。我还在考虑将每个 directorycopy() 调用放在不同的线程上(至少对于第一级目录,但不确定这是否是不好的做法)。

代码主要借鉴自:

https://docs.microsoft.com/en-us/dotnet/standard/io/how-to-copy-directories

我进行了更改以忽略 $Recycle Bin 文件夹,记录已更改或存在问题(例如长文件名)的文件,并仔细考虑如何处理异常。但最重要的是,我在复制之前添加了一个检查以查看哪个文件更新。

    private void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs)
    {
        // Get the subdirectories for the specified directory.
        DirectoryInfo dir = new DirectoryInfo(sourceDirName);
        if (sourceDirName.Contains("$")) // avoids $Recycle Bin
            return;

        if (!dir.Exists)
        {
            textb_Status.AppendText("Issue with " + dir.FullName + " This folder will not be compied.");
            return;
            //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);
            try
            {
                file.CopyTo(temppath);
            }
            catch (PathTooLongException)
            {
                textb_Status.AppendText("Filename Too long \n " + file.FullName + "\n");
            }
            catch (IOException ex)
            {
                FileInfo sourcefile = new FileInfo(file.FullName);
                FileInfo destFile = new FileInfo(temppath);
                int CompareValue = sourcefile.LastWriteTime.CompareTo(destFile.LastWriteTime); //<0==> Earlier (old)  =0 ==> same  >0 Later (newer)
                //textb_Status.AppendText("CompareValue: " + CompareValue + "\n");
                if (CompareValue > 0) // Represents newer file
                {
                    file.CopyTo(temppath, true);
                    textb_Status.AppendText("Updated: " + file.FullName + "\n");
                }
            }

            catch (Exception ex2)
            {
                textb_Status.AppendText("Issue with " + file.FullName + "\n");
                textb_Status.AppendText("Error Message \n");
                textb_Status.AppendText(ex2.Message + "\n");
            }

        }

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

如果只有几个文件要更新,我预计备份过程大约需要几分钟。

标签: c#file-io

解决方案


我不认为,减慢进程的不是数据量,而是文件数量。无论文件大小如何,初始文件访问(检查它是否存在,获取统计信息)都非常昂贵。此外,许多人认为将异常用于控制流的不良风格,并且抛出和捕获异常可能非常昂贵。从您的用例(即大多数文件未更改)来看,抛出了许多异常。

此外,根据您的磁盘(SSD 或 HDD),多线程读取和写入可能是一个非常糟糕的主意,并且会减慢整个过程。

并且根据File.Copy()您的实施情况可能会更好,首先检查目标,并且仅在Copy确实有必要时才这样做。但这是你只有在基准测试之后才能知道的事情。


推荐阅读