我必须在某些机器上同步大文件。这些文件最大可达6GB。同步将每隔几周手动完成。我不能考虑文件名,因为它们可以随时更改。
我的计划是在目标PC和源PC上创建校验和,然后将所有尚未在目标中的校验和文件复制到目标。 我的第一次尝试是这样的:
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);
}
}
问题是运行时:
- 使用带有1.6 GB文件的SHA256 - > 20分钟
- 使用带有1.6 GB文件的MD5 - > 6.15分钟
是否有更好 - 更快 - 获得校验和的方法(可能具有更好的散列函数)?
答案 0 :(得分:111)
这里的问题是SHA256Managed
一次读取4096个字节(继承自FileStream
并覆盖Read(byte[], int, int)
以查看它从文件流中读取的数量),这个数据太小了磁盘IO的缓冲区。
为了加快速度(使用SHA256在我的机器上散列2 Gb文件需要2分钟,在MD5上散布1分钟)在FileStream
中换BufferedStream
并设置合理大小的缓冲区大小(我试过〜 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
}
答案 1 :(得分:59)
不要校验整个文件,每100mb左右创建校验和,因此每个文件都有一组校验和。
然后在比较校验和时,您可以在第一个不同的校验和之后停止比较,提前退出,并避免处理整个文件。
相同的文件仍需要全部时间。
答案 2 :(得分:40)
正如Anton Gogolev所说,默认情况下,FileStream一次读取4096个字节, 但您可以使用FileStream构造函数指定任何其他值:
new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 16 * 1024 * 1024)
请注意,2004年Microsoft的Brad Abrams写道:
围绕a包装BufferedStream没有任何好处 的FileStream。我们将BufferedStream的缓冲逻辑复制到了 FileStream大约4年前鼓励更好的默认性能
答案 3 :(得分:22)
调用md5sum.exe的Windows端口。它的速度大约是.NET实现速度的两倍(至少在使用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 ();
}
答案 4 :(得分:15)
好的 - 感谢你们所有人 - 让我把它包起来:
答案 5 :(得分:11)
我使用缓冲区大小进行测试,运行此代码
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();
}
我测试了一个29½GB的文件,结果是
我正在运行i5 2500K CPU,12 GB RAM和OCZ Vertex 4 256 GB SSD驱动器。
所以我想,标准2TB硬盘怎么样?结果就像这样
所以我建议不要使用缓冲区或最大1毫米的缓冲区。
答案 6 :(得分:3)
您可以看看XxHash.Net(https://github.com/wilhelmliao/xxHash.NET)
xxHash算法似乎比所有其他算法都快。
xxHash网站上的一些基准测试:https://github.com/Cyan4973/xxHash
PS:我尚未使用它。
答案 7 :(得分:2)
你做错了什么(可能是读取缓冲区太小)。在一台年龄不同的机器上(从2002年开始的Athlon 2x1800MP),磁盘上的DMA可能不合适(6.6M / s在执行顺序读取时非常慢):
使用“随机”数据创建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慢(重复几次)。
答案 8 :(得分:0)
我知道我参加聚会很晚,但是在实际实施解决方案之前进行了测试。
我确实针对内置的MD5类以及md5sum.exe进行了测试。以我为例,内置类每次运行耗时13秒,其中md5sum.exe大约也需要16-18秒。
DateTime current = DateTime.Now;
string file = @"C:\text.iso";//It's 2.5 Gb file
string output;
using (var md5 = MD5.Create())
{
using (var stream = File.OpenRead(file))
{
byte[] checksum = md5.ComputeHash(stream);
output = BitConverter.ToString(checksum).Replace("-", String.Empty).ToLower();
Console.WriteLine("Total seconds : " + (DateTime.Now - current).TotalSeconds.ToString() + " " + output);
}
}