在C#中为大文件创build校验和的最快方法是什么?
我必须在一些机器上同步大文件。 这些文件的大小可以达到6GB。 同步将每几周手动完成。 我不能考虑文件名,因为他们可以随时更改。
我的计划是在目标PC和源PC上创build校验和,然后将所有不在目标中的校验和的文件复制到目的地。 我的第一个尝试是这样的:
using System.IO; using System.Security.Cryptography; private static string GetChecksum(string file) { using (FileStream stream = File.OpenRead(file)) { SHA256Managed sha = new SHA256Managed(); byte[] checksum = sha.ComputeHash(stream); return BitConverter.ToString(checksum).Replace("-", String.Empty); } }
问题在于运行时间:
– SHA256与一个1,6 GB的文件 – > 20分钟
– 与MD5的1,6 GB的文件 – > 6.15分钟
有没有更好的方法来获得校验和(也许有更好的散列函数)?
这里的问题是SHA256Managed
读取4096个字节(从FileStream
inheritance并覆盖Read(byte[], int, int)
以查看从文件stream中读取多less),这对于磁盘IO来说太小了。
为了加快速度(在我的机器上使用SHA256散列2 Gb文件2分钟,MD5使用1分钟)在BufferedStream
包装FileStream
,并设置合理大小的缓冲区大小(我尝试使用〜1 Mb缓冲区):
// Not sure if BufferedStream should be wrapped in using block using(var stream = new BufferedStream(File.OpenRead(filePath), 1200000)) { // The rest remains the same }
不要校验整个文件,每100mb左右创build校验和,因此每个文件都有一个校验和集合。
然后在比较校验和时,可以在第一次不同的校验和之后停止比较,提早出来,并且不用处理整个文件。
它仍然需要全部时间来完成相同的文件。
正如Anton Gogolev指出的,FileStream默认一次读取4096个字节,但是您可以使用FileStream构造函数指定任何其他值:
new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 16 * 1024 * 1024)
请注意,微软的Brad Abrams在2004年写道:
在FileStream周围包装BufferedStream没有任何好处。 我们在4年前将BufferedStream的缓冲逻辑复制到FileStream中,以鼓励更好的默认性能
资源
调用md5sum.exe的Windows端口。 这大约是.NET实现的两倍(至less在我的机器上使用1.2 GB的文件)
public static string Md5SumByProcess(string file) { var p = new Process (); p.StartInfo.FileName = "md5sum.exe"; p.StartInfo.Arguments = file; p.StartInfo.UseShellExecute = false; p.StartInfo.RedirectStandardOutput = true; p.Start(); p.WaitForExit(); string output = p.StandardOutput.ReadToEnd(); return output.Split(' ')[0].Substring(1).ToUpper (); }
好的 – 谢谢大家 – 让我把这个包起来:
- 使用“本机”EXE做哈希花了6分钟到10秒的时间,这是巨大的。
- 增加缓冲区速度更快 – 1.6GB文件需要5.2秒使用.net中的MD5,所以我会去这个解决scheme – 再次感谢
我做了缓冲区大小的testing,运行这个代码
using (var stream = new BufferedStream(File.OpenRead(file), bufferSize)) { SHA256Managed sha = new SHA256Managed(); byte[] checksum = sha.ComputeHash(stream); return BitConverter.ToString(checksum).Replace("-", String.Empty).ToLower(); }
我testing了一个29½GB的文件,结果是
- 10.000:369,24s
- 100.000:362,55s
- 1.000.000:361,53s
- 10.000.000:434,15s
- 100.000.000:435,15s
- 1,000,000,000:434,31s
- 而376,22的时候使用原始的,没有缓冲的代码。
我正在运行一个i5 2500K CPU,12 GB RAM和一个OCZ Vertex 4 256 GB SSD驱动器。
所以我想,怎么样一个标准的2TB硬盘。 结果是这样的
- 10.000:368,52s
- 100.000:364,15s
- 1.000.000:363,06s
- 10.000.000:678,96s
- 100.000.000:617,89s
- 1.000.000.000:626,86s
- 没有缓冲368,24
所以我会build议不要缓冲区或最大1磨的缓冲区。
你做错了什么(可能太小的读取缓冲区)。 在一个年龄不太老的机器上(从2002年开始Athlon 2x1800MP),在磁盘上有DMA(6.6M / s,在连续读取的时候速度很慢):
用“随机”数据创build一个1G文件:
# dd if=/dev/sdb of=temp.dat bs=1M count=1024 1073741824 bytes (1.1 GB) copied, 161.698 s, 6.6 MB/s # time sha1sum -b temp.dat abb88a0081f5db999d0701de2117d2cb21d192a2 *temp.dat
1m5.299s
# time md5sum -b temp.dat 9995e1c1a704f9c1eb6ca11e7ecb7276 *temp.dat
1m58.832s
这也是奇怪的,md5对我来说一直比sha1慢(reran几次)。