如何在将文件保存到磁盘时使用流计算哈希值?

我不想:首先保存文件,然后从磁盘加载它,只是为了计算散列,在任何时候必须将整个文件加载到内存中,使用有异步对应的方法的非异步版本,或者使用在.NET6或更高版本中标记为过时的API.

这就是我到目前为止一直得"err"分的东西

  public async Task HashOnTheFly()
  {
    var path = "/tmp/a.txt";
    await SaveAsync(File.OpenRead(path), "/tmp/b.txt", default);

    async Task SaveAsync(Stream stream, string path, CancellationToken ct)
    {
      var sha512 = SHA512.Create();
      var fileName = Path.GetFileName(path);
      var destinationPath = Path.Combine("/tmp", fileName);
      await using var fileStream = File.Create(destinationPath);

      await using var cryptoStream = new CryptoStream(fileStream, sha512, CryptoStreamMode.Read);
      await stream.CopyToAsync(fileStream, ct);

      if (sha512?.Hash is { } computedHash)
        Console.WriteLine(computedHash);
      else
        Console.WriteLine("err");
    }
  }

推荐答案

您的代码中有一些错误:

  1. 你永远不会复制到CryptoStream,你只能复制到底层的fileStream.因此,自然不会计算任何散列.

  2. 在try 确定散列之前,您不会关闭CryptoStream.必须首先关闭流,以确保计算并刷新所有数据.

  3. 因为您是在编写时计算散列,所以必须使用100而不是CryptoStreamMode.Read.

  4. SHA512实现IDisposable等应该通过using语句来处理.

因此,您的SaveAsync应该修改如下:

async Task<byte []> SaveAsync(Stream stream, string path, CancellationToken ct)
{
    var fileName = Path.GetFileName(path);
    var destinationPath = Path.Combine("/tmp", fileName);

    using var sha512 = SHA512.Create();
    await using (var fileStream = File.Create(path, 0, FileOptions.Asynchronous))
    await using (var cryptoStream = new CryptoStream(fileStream, sha512, CryptoStreamMode.Write))
    {
        await stream.CopyToAsync(cryptoStream, ct);
    }
    
    if (sha512?.Hash is { } computedHash)
        Console.WriteLine(Convert.ToBase64String(computedHash));
    else
        Console.WriteLine("err");
    
    return sha512.Hash;
}

备注:

  • 当您正在进行异步I/O时,您可能想要打开带有FileOptions.AsynchronousfileStream,以指示该文件可用于异步读写.

  • 我修改了您的代码以返回计算的散列,因为这样做似乎是合乎逻辑的.

演示小提琴here.

Csharp相关问答推荐

AutoMapper -如何为两个不同的用例设置单个映射?

将修剪声明放入LINQ中

需要深入了解NpgSQL DateTimeOffset处理

ASP.NET Core:如何在IPageFilter中注入ApplicationDbContext

EF Core 8—应用客户端投影后无法转换集操作

Blazor. NET 8—阶段启动配置文件不启动网站VS2022

如何将Kafka消息时间戳转换为C#中的日期和时间格式?

注册所有IMediatR类

Razor视图Razor页面指向同一端点时的优先级

为什么在使用动态obj+类obj时会调用串联?

Polly重试URL复制值

.NET:从XPath定位原始XML文档中的 node

正在寻找新的.NET8 Blazor Web应用程序.如何将.js添加到.razor页面?

如何返回具有泛型的类?

在.NET8中如何反序列化为私有字段?

FakeItEasy自动嘲弄内容

Azure函数正在返回值列表,但该列表在Chrome中显示为空

try 访问字典中的模拟对象时引发KeyNotFoundException

ASP.NET核心中的验证错误-该字段为必填字段

在Word Open OpenXML c#上应用葡萄牙语字符Times New Roman时出错