在 C# 中执行 MD5 并一次下载的有效方法是什么?
What is an efficient way in C# of doing MD5 and download all at once?
我正在下载,然后进行 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);
编辑: 为 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();
}
}
类似这样。
byte[] result;
using (var webClient = new System.Net.WebClient())
{
result = webClient.DownloadData("http://some.url");
}
byte[] hash = ((HashAlgorithm)CryptoConfig.CreateFromName("MD5")).ComputeHash(result);
如果您谈论的是大文件(我假设超过 1GB),您将希望以块的形式读取数据,然后通过 MD5 算法处理每个块,然后将其存储到磁盘。这是可行的,但我不知道有多少默认的 .NET 类 可以帮助你。
一种方法可能是使用自定义流包装器。首先,您从 WebClient 获得一个 Stream
(通过 GetWebResponse()
and then GetResponseStream()
), then you wrap it, and then pass it to ComputeHash(stream)
。当 MD5 在您的包装器上调用 Read()
时,包装器将在网络流上调用 Read
,当收到,然后传回MD5。
我不知道如果你这样做会有什么问题等着你。
Is there a good, clean way of computing the MD5 as part of the download stream? Ideally, the MD5 should just fall out of the DownloadFile()
function as a side effect of sorts.
您可以遵循此策略,进行 "chunked" 计算并最大程度地减少内存压力(和重复):
- 在 Web 客户端上打开响应流。
- 打开目标文件流。
- 在有可用数据时重复:
- 从响应流中读取块到字节缓冲区
- 写入目标文件流。
- 使用
TransformBlock
方法将字节加入hash计算
- 使用
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;
}
}
}
}
}
我正在下载,然后进行 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);
编辑: 为 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();
}
}
类似这样。
byte[] result;
using (var webClient = new System.Net.WebClient())
{
result = webClient.DownloadData("http://some.url");
}
byte[] hash = ((HashAlgorithm)CryptoConfig.CreateFromName("MD5")).ComputeHash(result);
如果您谈论的是大文件(我假设超过 1GB),您将希望以块的形式读取数据,然后通过 MD5 算法处理每个块,然后将其存储到磁盘。这是可行的,但我不知道有多少默认的 .NET 类 可以帮助你。
一种方法可能是使用自定义流包装器。首先,您从 WebClient 获得一个 Stream
(通过 GetWebResponse()
and then GetResponseStream()
), then you wrap it, and then pass it to ComputeHash(stream)
。当 MD5 在您的包装器上调用 Read()
时,包装器将在网络流上调用 Read
,当收到,然后传回MD5。
我不知道如果你这样做会有什么问题等着你。
Is there a good, clean way of computing the MD5 as part of the download stream? Ideally, the MD5 should just fall out of the
DownloadFile()
function as a side effect of sorts.
您可以遵循此策略,进行 "chunked" 计算并最大程度地减少内存压力(和重复):
- 在 Web 客户端上打开响应流。
- 打开目标文件流。
- 在有可用数据时重复:
- 从响应流中读取块到字节缓冲区
- 写入目标文件流。
- 使用
TransformBlock
方法将字节加入hash计算
- 使用
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;
}
}
}
}
}