我正在下载,然后MD5检查以确保下载成功。我有下面的代码应该可以工作,但不是最有效的-特别是对于大文件。
using (var client = new System.Net.WebClient())
{
client.DownloadFile(url, destinationFile);
}
var fileHash = GetMD5HashAsStringFromFile(destinationFile);
var successful = expectedHash.Equals(fileHash, StringComparison.OrdinalIgnoreCase);
我担心的是字节都流式传输到磁盘,然后MD5 ComputeHash()
必须打开文件并再次读取所有字节。有没有一种好的,干净的方法来计算MD5作为下载流的一部分?理想情况下,MD5应该只是作为一种副作用从DownloadFile()
函数中分离出来。具有如下签名的函数:
string DownloadFileAndComputeHash(string url, string filename, HashTypeEnum hashType);
Edit:为GetMD5HashAsStringFromFile()
添加代码
public string GetMD5HashAsStringFromFile(string filename)
{
using (FileStream file = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
{
var md5er = System.Security.Cryptography.MD5.Create();
var md5HashBytes = md5er.ComputeHash(file);
return BitConverter
.ToString(md5HashBytes)
.Replace("-", string.Empty)
.ToLower();
}
}
是否有一个好的,干净的方法来计算MD5作为下载流的一部分?理想情况下,MD5应该只是作为排序的副作用从
DownloadFile()
函数中分离出来。
您可以遵循以下策略,进行"分块"计算并最小化内存压力(和重复):
- 在web客户端打开响应流。
- 打开目标文件流
- 有数据时重复:
- 从响应流中读取块到字节缓冲区
- 写入目标文件流
- 使用
TransformBlock
方法将字节添加到哈希计算
- 使用
TransformFinalBlock
获取计算出的哈希码
下面的示例代码展示了如何实现这一点。
public static byte[] DownloadAndGetHash(Uri file, string destFilePath, int bufferSize)
{
using (var md5 = MD5.Create())
using (var client = new System.Net.WebClient())
{
using (var src = client.OpenRead(file))
using (var dest = File.Create(destFilePath, bufferSize))
{
md5.Initialize();
var buffer = new byte[bufferSize];
while (true)
{
var read = src.Read(buffer, 0, buffer.Length);
if (read > 0)
{
dest.Write(buffer, 0, read);
md5.TransformBlock(buffer, 0, read, null, 0);
}
else // reached the end.
{
md5.TransformFinalBlock(buffer, 0, 0);
return md5.Hash;
}
}
}
}
}
如果您谈论的是大文件(我假设超过1GB),那么您将希望以块为单位读取数据,然后通过MD5算法处理每个块,然后将其存储到磁盘上。这是可行的,但我不知道有多少默认的。net类能帮到你。
一种方法可能是使用自定义流包装器。首先,您从WebClient(通过GetWebResponse()
和GetResponseStream()
)获得Stream
,然后将其包装,然后将其传递给ComputeHash(stream)
。当MD5调用包装器上的Read()
时,包装器将调用网络流上的Read
,在接收到数据时将数据写出来,然后将其传递回MD5。
我不知道如果你这么做会有什么问题等着你。
就像这样。
byte[] result;
using (var webClient = new System.Net.WebClient())
{
result = webClient.DownloadData("http://some.url");
}
byte[] hash = ((HashAlgorithm)CryptoConfig.CreateFromName("MD5")).ComputeHash(result);