有比File.Copy更快的文件复制方式吗?

19

在同一个驱动器上,从文件夹A复制一个1.6GB的文件到文件夹B需要大约2分钟的时间用 File.Copy(src, dest); 。有没有更快的方法在C#/.NET中实现(无需硬件)-例如使用流、线程等?

使用文件流会更快吗?还有一种通过线程池分块读取/写入字节范围的类,这种方式听起来很容易破坏文件完整性,但速度是第一位的,而不是完整性。

我已经搜索过,但每个人都说要使用File.Copy,但它很慢(和Windows Copy一样慢)- 我不想使用第三方工具。


以下是一些问题的答案:

复制时间比较:

> C# : 2.15m  
> Windows Explorer: 2.53m  
> TeraCopy: 2.26m
> FastCopy: 2.24m

好的,那些不是平均值,我知道它们可能会在后续运行中稍微改变,但我真的认为复制文件会有一种更快的方法,因为我认为Windows正在进行其他安全和完整性检查 :-(

我仍然希望能得到一些好的答案(比如说,“哦,是的,如果你使用缓冲区 m 并关闭安全性,1.5GB以上的文件将会快 x ”) - 在这一点上,我只是期望。


12
我认为在Windows系统上,很难找到比Windows自身更快的文件复制方式。 - Steven Evers
我假设你的驱动器是传统的盘片式驱动器。如果是这样,分块文件可能会因为寻道时间而减慢速度。 - Greg
将1.6GB复制到同一驱动器上的新位置并不是对硬盘非常友好的活动。它必须在各个位置跳跃以支持同时读写。 - Kirk Woll
2
TeraCopy使用动态调整的缓冲区来减少寻道时间。 - dtb
你尝试过在备份模式下测量RoboCopy吗?这通常比正常模式快得多。如果备份模式更快,请在问题中指出,可能会有其他答案出现。复制操作肯定会变慢的是在同一驱动器上进行复制。现在需要进行大量寻道,这通常会严重减慢复制操作。不同驱动器之间的速度如何? - Jeroen Wiert Pluimers
显示剩余8条评论
8个回答

8
如果你想创建一个符号链接或硬链接而不是实际的副本,那么以下的Windows API可能会有所帮助。

7
移山最快的方法不是去移动山,而是根本不去动它。 - dthorpe
符号链接会带来什么优势?我正在努力理解这个问题,并使用P/Invoke进行了一个示例-如果我尝试new FileInfo("symbolicFileName.txt").Name,它会返回名称,但是如果我尝试File.Open("symbolicFileName.txt", .....),它会说找不到文件。我在SymbolicLink上找到的信息对于真正解释它是什么以及如何使我受益而言都相当无用。我真正想要的是修改文件,如果一切顺利,替换原始文件,我一直在使用File.Copy两种方式来实现这一点。 - schmoopy
2
@schmoopy:在这种情况下,这个答案对你没有任何帮助。硬链接和符号链接基本上是文件系统指针。因此,如果您尝试修改从硬链接打开的文件,则会更改原始文件的内容。请随意在我的答案上投反对票。我会投,但您不能对自己投反对票。保留答案仍然可能有用,否则我将删除它。 - Brian Gideon
我不会给你踩反对票,我很欣赏你的意见,而且这种方法对其他人也可能有用。 :-) - schmoopy

5
你可以尝试使用已有的硬件,并在内存中分配一个大缓冲区。通过以更大的块读写,你可能能够消除一些开销。
然而,要去除的开销并不多,瓶颈仍然是磁盘I/O。我预计最多只能减少5%的执行时间。

5

File.Copy调用Kernel32.dll中的CreateFile。如果您正在复制大量非常小的文件(例如数百万个),那么通过进行P/Invoke调用来玩弄参数并跳过权限需求可能是值得的。对于一个大文件,99.999%的2分钟时间都花在驱动程序代码内部。


2
我认为Windows的copy、file.copy和Copyfile都使用相同的底层操作系统调用来完成复制。我怀疑你写的任何内容都无法超越操作系统内部的调用性能。

2

我没有尝试过这个方法,但它可能会很快。

使用两个内存映射,一个映射到输入文件,一个映射到输出文件,并将内存从一个映射移动到另一个映射。由操作系统执行的页面映射被调整为最高性能,因为它会影响整个系统的速度。


我也想到了这个想法,不过有一个小变化:你知道是否可能对两个映射视图之间的字节进行memcpy,而是仅使用单个视图,首先将其映射到源上,然后显式地要求整个VirtualAlloc范围,然后以某种方式切换内存映射文件视图到目标文件,保持该内存不变,这意味着最后你所要做的只是简单地对范围执行FlushViewOfFile - Glenn Slayden
@GlennSlayden 我不知道有什么方法可以做到这一点。如果你能想出一个方法,那就值得留下你自己的答案。 - Mark Ransom

1
对于单个文件,在同一驱动器上进行来回操作,你的问题的答案是:没有
对于网络传输、移动大量文件和其他更复杂的情况,可能有改进的空间。
如果你当前的需求是将 GB 的数据复制到同一磁盘上的第二个物理(非符号)位置,那么提高性能的最佳方法可能是使用更快的磁盘。

0

我认为你应该首先检查你的磁盘有多少碎片。如果你的文件被分成许多部分,并且没有足够的连续空闲空间来存储第二个文件,那么磁盘必须经常移动磁头,这非常慢。

也许你的磁盘很老旧而且速度很慢,已经达到了最大性能。在这种情况下,解决方案很简单,你需要购买一个新的,或者更好的是两个并创建RAID 0。

你还可以检查是否在复制过程中有其他程序正在使用同一磁盘,例如反病毒软件或索引服务。

我没有提出任何软件解决方案,因为我不相信有比操作系统提供的功能更快的东西。


0

一切都取决于操作系统在复制时的分配,如果文件在缓存中(以相同方式重复5次以避免此情况)。

最清晰的结果是多次重复测试。


请检查我的解决方案:https://dev59.com/WG445IYBdhLWcg3wq8Pp - pankaj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接