在c#中执行MD5并同时下载的有效方法是什么?

本文关键字:下载 有效 方法 是什么 执行 MD5 | 更新日期: 2023-09-27 17:49:15

我正在下载,然后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();
        }
    }

在c#中执行MD5并同时下载的有效方法是什么?

是否有一个好的,干净的方法来计算MD5作为下载流的一部分?理想情况下,MD5应该只是作为排序的副作用从DownloadFile()函数中分离出来。

您可以遵循以下策略,进行"分块"计算并最小化内存压力(和重复):

  1. 在web客户端打开响应流。
  2. 打开目标文件流
  3. 有数据时重复:
    • 从响应流中读取块到字节缓冲区
    • 写入目标文件流
    • 使用TransformBlock方法将字节添加到哈希计算
  4. 使用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);