可能用缓冲读取来计算MD5(或其他)散列?
我需要计算相当大的文件(千兆字节)的校验和。 这可以使用以下方法来完成:
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框架中找不到像这样的重写,我在做梦吗? 它从来没有存在过,还是我只是在search? 同时进行写入和校验和计算的原因是由于大文件造成的。
您使用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;
注意:它起作用(至less在MD5提供程序中)将所有块发送到TransformBlock
,然后将空块发送到TransformFinalBlock
以完成该过程。
我喜欢上面的答案,但为了完整起见,作为更一般的解决scheme,请参阅CryptoStream
类。 如果你已经处理了stream,很容易把你的stream封装到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));
在得到散列之前,你可能不得不closuresstream(所以HashAlgorithm
知道它已经完成了)。
似乎可以使用TransformBlock
/ TransformFinalBlock
,如下例所示: 散列大文件时显示进度更新
预期散列algorithm可以处理这种情况,通常用3个函数来实现:
hash_init()
– 调用来分配资源并开始散列。
hash_update()
– 在新数据到达时调用。
hash_final()
– 完成计算和空闲资源。
请看http://www.openssl.org/docs/crypto/md5.html或http://www.openssl.org/docs/crypto/sha.html,获取C语言中的标准示例;; 我相信你的平台有类似的库。
我只是不得不做类似的事情,但想要asynchronous读取文件。 它使用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); } }