.net File.Copy复制许多小文件时(非networking)很慢,

我正在为自己制作一个简单的文件夹同步备份工具,并使用File.Copy进入相当的包版。 做testing复制约44,000小文件(Windows邮件文件夹)的文件夹到我系统中的另一个驱动器,我发现使用File.Copy比使用命令行和运行xcopy复制相同的文件/文件夹慢3倍。 我的C#版本需要超过16分钟才能复制文件,而xcopy只需要5分钟。 我试过在这个主题上寻找帮助,但是我发现所有人都抱怨通过networking缓慢地拷贝大文件。 这既不是一个大文件问题,也不是一个networking复制问题。

我发现了一个关于更好的File.Copyreplace的有趣的文章 ,但是发布的代码有一些导致堆栈问题的错误,而我没有足够的知识来解决他的代码中的问题。

有没有什么常见或简单的方法来更快地取代File.Copy?

有一件事要考虑的是你的副本是否有一个在复制期间更新的用户界面。 如果是这样,请确保您的副本在单独的线程上运行,或者您的UI在复制过程中都会冻结,并通过阻止调用来更新UI来降低副本的速度。

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

另外如果你有一个用户界面,不要更新每个文件; 而是更新每个X兆字节或每个Y文件(以先到者为准),这样可以将更新量降低到UI实际可以处理的程度。 我使用了每个.5MB或10个文件; 那些可能不是最佳的,但它显着提高了我的复制速度和UI响应。

另一种加快速度的方法是使用Enumerate函数而不是Get函数(例如EnumerateFiles而不是GetFiles )。 这些函数会尽快开始返回结果,而不是在列表完成时返回所有内容。 它们返回一个Enumerable,所以你可以调用foreach的结果:foreach( System.IO.Directory.EnumerateDirectories(path))字符串文件System.IO.Directory.EnumerateDirectories(path)) 。 对于我的程序来说,这在速度上也有明显的不同,在处理包含许多文件的目录的情况下会更有帮助。

减慢IO操作速度的一个因素是旋转磁盘上最大的动作是移动磁盘头。

这是合理的假设,可能相当准确的是,你的许多小文件(都是相互关联的)在磁盘上比靠近拷贝的目的地更接近(假设你是从磁盘的一部分到同一磁盘的另一部分)。 如果复制一下,然后写一会儿,你打开一个机会窗口的其他进程来移动源磁盘或目标磁盘上的磁盘头。

XCopy比Copy更好的地方在于,XCopy读入一堆文件,然后开始将这些文件写出到目的地。

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

如果您从一个磁盘读取数据并写入另一个磁盘,请尝试启动一个线程以从源磁盘读取数据,另一个线程写入另一个磁盘。

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

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

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

如果源和目标是相同的磁盘,则:

  • 读一个固定的字节块,每次说8K,不管有多少个文件。
  • 把这个固定的块写到目的地,无论是在一个文件中还是在多个文件中。

这样你会得到显着的表现。

另一种方法是你只需从你的.net代码调用xcopy。 为什么要使用File.Copy来做这件事。 您可以使用Process.StandardOutput捕获xcopy输出,并在屏幕上显示以显示用户正在进行的操作。

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

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

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