关于加快硬盘备份代码的建议



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

该代码主要借用自:

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

我做了一些更改,忽略了$RecycleBin文件夹,记录了已经更改或存在问题的文件,如文件名过长,以及在处理异常时的谨慎态度。但最重要的是,在复制之前,我添加了一个检查,以查看哪个文件更新。

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

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

我不认为是数据量减缓了进程,而是文件数量。无论文件大小如何,初始文件访问(检查是否存在,获取统计数据)都非常昂贵。此外,许多人认为对控制流使用异常是一种糟糕的风格,抛出和捕获异常可能非常昂贵。从您的用例(即大多数文件没有变化)来看,抛出了许多异常。

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

根据File.Copy()的实现,您可能会更好,首先检查目标,只有在真正必要的情况下才执行Copy。但这是你只有在基准之后才能知道的。

谢谢@derpirscher。对于每个文件,我在尝试编写之前都会检查它是否存在。这样,就不会抛出异常。驱动器在大约5秒内检查完毕!我修改了源目录中的一些文件,以确保它们被检测到并复制。确实如此。

我感觉到例外很贵,我只是不知道它有这么糟糕。。。。伟大的教训!

我的代码在下面。注意:当我试图从系统卷信息文件夹中获取文件时,收到了错误,所以我开始检查以确保sourceDirName不等于该目录。

private void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs)
{
if (sourceDirName.Contains("System Volume Information"))
return;
//textb_Status.AppendText("Current Directory: " + sourceDirName +"n");
DirectoryInfo[] dirs = null;
// 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);
}
{
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
{
if (File.Exists(temppath)) // Check for newer
{
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");
}
}
else
{
file.CopyTo(temppath);
}
}
catch (PathTooLongException)
{
textb_Status.AppendText("Filename Too long rnn " + file.FullName + "rnn");
}
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 + "nn");
}
}

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

最新更新