C# 是否可以使用缓冲读取计算MD5(或其他)哈希?
我需要计算相当大的文件(GB)的校验和。这可以使用以下方法完成:C# 是否可以使用缓冲读取计算MD5(或其他)哈希?,c#,.net-3.5,hash,md5,buffer,C#,.net 3.5,Hash,Md5,Buffer,我需要计算相当大的文件(GB)的校验和。这可以使用以下方法完成: private byte[] calcHash(string file) { System.Security.Cryptography.HashAlgorithm ha = System.Security.Cryptography.MD5.Create(); FileStream fs = new FileStream(file, FileMode.Open, FileAccess.
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(或其他)散列,即:计算一个缓冲区的散列,然后将结果散列输入下一次迭代
类似这样的:(伪代码ish)
哈希现在与在整个文件上运行calcHash函数所能实现的非常相似
现在,我在.NET3.5框架中找不到任何这样的覆盖,我是在做梦吗?它从未存在过,还是我只是不善于寻找?同时执行写入和校验和计算的原因是,由于文件很大,所以这很有意义 散列算法有望处理这种情况,通常使用3个函数实现:
hash\u init()
-调用以分配资源并开始哈希。hash\u update()
-在新数据到达时调用。hash_final()
-完成计算并释放资源。看一看C语言中的好的、标准的例子;我相信您的平台也有类似的库。您可以使用
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;
注意:它可以将所有块发送到
TransformBlock
,然后将空块发送到TransformFinalBlock
,以完成流程。似乎您可以使用TransformBlock
/TransformFinalBlock
,如本示例所示:我喜欢上面的答案,但为了完整性和更一般的解决方案,请参考CryptoStream
类。如果您已经在处理流,则很容易将流包装在加密流
中,将哈希算法
作为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));
在获取散列之前,您可能必须关闭流(因此
散列算法
知道它已经完成)。我刚刚不得不做一些类似的事情,但希望异步读取文件。它使用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);
}
}
专用静态异步任务CalculateMD5Async(字符串fullFileName)
{
var block=ArrayPool.Shared.Rent(8192);
尝试
{
使用(var md5=md5.Create())
{
使用(var stream=newfilestream(fullFileName,FileMode.Open,FileAccess.Read,FileShare.Read,8192,true))
{
整数长度;
while((length=await stream.ReadAsync(block,0,block.length).ConfigureAwait(false))>0)
{
md5.TransformBlock(block,0,length,null,0);
}
md5.TransformFinalBlock(块,0,0);
}
var hash=md5.hash;
返回Convert.tobase64字符串(散列);
}
}
最后
{
ArrayPool.Shared.Return(块);
}
}
答案很好,但问题的“它在.net中的位置?”部分仍然悬而未决。@Pascal:请参阅下面的两个好答案,这两个答案都是在您发表评论之前发布的。哎,caramba!就在那里!这就是我正在寻找的功能。很高兴知道这一切都不是我编造的。感谢Guffa和Rubens及时提供了正确答案+1对于你们两个,我将接受这个答案,因为包含了代码示例。请注意,在调用TransformBlock时,您可以将block
的第二个实例等效地替换为null
;实际上,您并不希望发生任何复制;输出参数实际上没有对哈希做任何操作。此外,TransformFinalBlock的长度可以为零。是否可以转换前X个数据块,转储状态数据,然后在恢复新计算的状态后继续下一个数据块?。在云解决方案中有100GB的文件,能够不必一次过检查漏洞文件就好了。机器可以回收ect。@pksorensen:我不这么认为,我没有看到任何获取或设置MD5对象的计算状态的方法或属性。理论上,这当然是可能的,但您可能需要使用该算法的单独实现,以便添加处理状态的方法。该链接已失效,请尝试以下操作:What'sArrayPool
?确定:需要安装程序包。
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);
}
}