10

我正在为自己制作一个简单的文件夹同步备份工具,但在使用 File.Copy 时遇到了很大的障碍。在测试将一个包含约 44,000 个小文件(Windows 邮件文件夹)的文件夹复制到我系统中的另一个驱动器时,我发现使用 File.Copy 比使用命令行和运行 xcopy 复制相同的文件/文件夹慢 3 倍以上。我的 C# 版本需要 16 多分钟来复制文件,而 xcopy 只需要 5 分钟。我曾尝试寻求有关此主题的帮助,但我发现的只是人们抱怨通过网络复制大文件的速度很慢。这既不是大文件问题,也不是网络复制问题。

我发现了一篇关于更好的 File.Copy 替换的有趣文章,但是发布的代码有一些错误,这会导致堆栈出现问题,而且我远没有足够的知识来解决他的代码中的问题。

是否有任何常见或简单的方法可以用更快的方法替换 File.Copy?

4

5 回答 5

9

要考虑的一件事是您的副本是否具有在副本期间更新的用户界面。如果是这样,请确保您的副本在单独的线程上运行,否则您的 UI 将在复制期间冻结,并且通过阻塞调用更新 UI 会减慢复制速度。

xcopy我编写了一个类似的程序,根据我的经验,我的代码比 Windows 资源管理器副本运行得更快(从命令提示符不确定)。

此外,如果您有 UI,请不要更新每个文件;而是更新每 X MB 或每 Y 个文件(以先到者为准),这样可以减少 UI 实际可以处理的更新量。我每 .5MB 或 10 个文件使用一次;这些可能不是最佳的,但它显着提高了我的复制速度和 UI 响应能力。

另一种加快速度的方法是使用 Enumerate 函数而不是 Get 函数(例如EnumerateFiles,而不是GetFiles)。这些函数会尽快开始返回结果,而不是在列表构建完成后等待返回所有内容。它们返回一个 Enumerable,因此您可以在结果上调用 foreach:foreach(string file in System.IO.Directory.EnumerateDirectories(path))。对于我的程序,这也对速度产生了显着影响,并且在像您这样处理包含目录的情况下会更有帮助许多文件。

于 2012-07-06T23:24:53.953 回答
5

在旋转磁盘上最能减慢 IO 操作的一件事是移动磁盘磁头。

可以合理地假设并且可能非常准确,您的许多小文件(都相互关联)在磁盘上的距离比它们与副本目标的距离更近(假设您正在从磁盘的一部分进行复制)到同一磁盘的另一部分)。如果您先复制一点,然后再写入一点,您就会为其他进程打开一个机会窗口,让其他进程移动源磁盘或目标磁盘上的磁头。

XCopy 比 Copy 做得更好的一件事(在这两种情况下都是命令)是 XCopy 在开始将这些文件写出到目标之前读取了一堆文件。

如果您要在同一个磁盘上复制文件,请尝试分配一个大缓冲区以一次读取多个文件,然后在缓冲区已满时写出这些文件)。

如果您正在从一个磁盘读取并写入另一个磁盘,请尝试启动一个线程以从源磁盘读取,并启动一个单独的线程以写入另一个磁盘。

于 2012-07-06T23:02:41.647 回答
3

有两种更快的文件复制算法:

如果源和目标是不同的磁盘然后:

  • 一个线程连续读取文件并存储在缓冲区中。
  • 另一个线程从该缓冲区连续写入文件。

如果源和目标是同一个磁盘,则:

  • 读取固定的字节块,一次说 8K,不管有多少文件。
  • 将该固定块写入目标,在一个文件或多个文件中。

这样,您将获得显着的性能。

另一种选择是您只需从您的 .net 代码中调用 xcopy 。为什么要使用 File.Copy 来做这件事。您可以使用 Process.StandardOutput 捕获 xcopy 输出并在屏幕上显示,以便向用户显示正在发生的事情。

于 2012-07-09T14:24:44.940 回答
1

我认为您至少可以将其并行化,以便同时处理两个文件。当一个线程正在写入时,另一个线程可能已经在读取下一个文件。如果你有一个文件列表,你可以这样做。使用多个线程将无济于事,因为这将使驱动器移动更多,而不是能够顺序写入..

 var files = new List<string>();
 // todo: fill the files list using directoryenumeration or so...
 var po = new ParallelOptions() {MaxDegreeOfParallelism = 2};
 Parallel.ForEach(files, po, CopyAFile);

 // Routine to copy a single file
 private void CopyAFile(string file) { }
于 2012-07-09T11:34:03.627 回答
0

我在这个级别上没有很好的经验。为什么不尝试运行包含 xcopy 命令的批处理文件?检查这篇文章:在 C# 中执行批处理文件

于 2012-07-06T23:05:31.753 回答