[英]Possible to calculate MD5 (or other) hash with buffered reads?
我需要计算很大文件(千兆字节)的校验和。 可以使用以下方法完成此操作:
private byte[] calcHash(string file)
{
System.Security.Cryptography.HashAlgorithm ha = System.Security.Cryptography.MD5.Create();
FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read);
byte[] hash = ha.ComputeHash(fs);
fs.Close();
return hash;
}
但是,文件通常是事先以缓冲方式写入的(例如一次写入32mb)。 我如此确信,我看到了一个哈希函数的替代,该哈希函数使我能够在编写的同时计算MD5(或其他)哈希,即:计算一个缓冲区的哈希,然后将得到的哈希输入到下一个迭代中。
像这样的东西:(pseudocode-ish)
byte [] hash = new byte [] { 0,0,0,0,0,0,0,0 };
while(!eof)
{
buffer = readFromSourceFile();
writefile(buffer);
hash = calchash(buffer, hash);
}
哈希现在与在整个文件上运行calcHash函数所实现的功能类似。
现在,在.Net 3.5 Framework中找不到类似的替代项,我在做梦吗? 它从来没有存在过,还是我在搜索时很烂? 一次进行写入和校验和计算的原因是由于文件大而有意义。
我喜欢上面的答案,但是为了完整起见,并且是一个更通用的解决方案,请参阅CryptoStream
类。 如果您已经在处理流,则可以很容易地将流包装在CryptoStream
,并将HashAlgorithm
作为ICryptoTransform
参数传递。
var file = new FileStream("foo.txt", FileMode.Open, FileAccess.Write);
var md5 = MD5.Create();
var cs = new CryptoStream(file, md5, CryptoStreamMode.Write);
while (notDoneYet)
{
buffer = Get32MB();
cs.Write(buffer, 0, buffer.Length);
}
System.Console.WriteLine(BitConverter.ToString(md5.Hash));
您可能必须在获取哈希之前关闭流(因此HashAlgorithm
知道已完成)。
您可以使用TransformBlock
和TransformFinalBlock
方法来分块处理数据。
// Init
MD5 md5 = MD5.Create();
int offset = 0;
// For each block:
offset += md5.TransformBlock(block, 0, block.Length, block, 0);
// For last block:
md5.TransformFinalBlock(block, 0, block.Length);
// Get the has code
byte[] hash = md5.Hash;
注意:它可以(至少与MD5提供程序一起使用)将所有块发送到TransformBlock
,然后将空块发送到TransformFinalBlock
以完成该过程。
似乎可以使用TransformBlock
/ TransformFinalBlock
,如本示例所示:对大型文件进行哈希处理时显示进度更新
哈希算法有望处理这种情况,通常使用以下3个函数实现:
hash_init()
-调用以分配资源并开始哈希。
hash_update()
-在到达新数据时调用它。
hash_final()
-完成计算并释放资源。
请参阅http://www.openssl.org/docs/crypto/md5.html或http://www.openssl.org/docs/crypto/sha.html ,以获取有关C语言的良好标准示例; 我确定您的平台也有类似的库。
我只需要做类似的事情,但想异步读取文件。 它使用TransformBlock和TransformFinalBlock,并给我与Azure一致的答案,所以我认为这是正确的!
private static async Task<string> CalculateMD5Async(string fullFileName)
{
var block = ArrayPool<byte>.Shared.Rent(8192);
try
{
using (var md5 = MD5.Create())
{
using (var stream = new FileStream(fullFileName, FileMode.Open, FileAccess.Read, FileShare.Read, 8192, true))
{
int length;
while ((length = await stream.ReadAsync(block, 0, block.Length).ConfigureAwait(false)) > 0)
{
md5.TransformBlock(block, 0, length, null, 0);
}
md5.TransformFinalBlock(block, 0, 0);
}
var hash = md5.Hash;
return Convert.ToBase64String(hash);
}
}
finally
{
ArrayPool<byte>.Shared.Return(block);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.