在 UWP 中使用 IBuffer 计算文件的哈希值

Using IBuffer to compute hash of the file in UWP

我不知道如何在 UWP 中计算大文件的哈希值。哈希算法接受 IBuffer 接口作为数据参数,它无法从流中获取数据。只有两种方式看起来都是死胡同:

  1. 无法将整个文件加载到内存中,因为文件可能太大。
  2. 使用 IBuffer 接口实现某种流 reader 似乎也不可行,因为 IBuffer 只有两个属性:长度和容量。

这是来自 MSDN 的精简示例,它展示了当数据位于字符串中时如何使用算法。

IBuffer buffUtf8Msg = CryptographicBuffer.ConvertStringToBinary(strMsg, BinaryStringEncoding.Utf8);
HashAlgorithmProvider objAlgProv = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Md5);
IBuffer buffHash = objAlgProv.HashData(buffUtf8Msg);
string hex = CryptographicBuffer.EncodeToHexString(buffHash);

如何在不编写自己的算法或使用第三方组件的情况下计算 UWP 中大文件的 MD5 哈希值?

Hashing algorithm accepts IBuffer interface as data parameter which has no way to get data from the stream.

我们可以通过FileIO.ReadBufferAsync方法直接从文件中读取缓冲区。然后你可以散列它。代码如下:

   StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/P408.mp4"));
   IBuffer filebuffer = await FileIO.ReadBufferAsync(file);
   //IBuffer buffUtf8Msg = CryptographicBuffer.ConvertStringToBinary(strMsg, BinaryStringEncoding.Utf8);
   HashAlgorithmProvider objAlgProv = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Md5);
   IBuffer buffHash = objAlgProv.HashData(filebuffer);
   string hex = CryptographicBuffer.EncodeToHexString(buffHash);

Implementing some kind of stream reader with IBuffer interface does not seem viable either as IBuffer only has two properties: Length and Capacity

IInputStream.ReadAsync方法可以读取流到缓冲区。提供buffer参数读取InputStream到buffer。如果要读取大文件,可以定义buffer的capacity到读取文件的区段。代码如下:

HashAlgorithmProvider alg = HashAlgorithmProvider.OpenAlgorithm(HashAlgorithmNames.Md5);
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///Assets/P408.mp4"));
var stream = await file.OpenStreamForReadAsync();
var inputStream = stream.AsInputStream();
uint capacity = 100000000;
Windows.Storage.Streams.Buffer buffer = new Windows.Storage.Streams.Buffer(capacity);
var hash = alg.CreateHash();
while (true)
{
    await inputStream.ReadAsync(buffer, capacity, InputStreamOptions.None);
    if (buffer.Length > 0)
        hash.Append(buffer);
    else
        break;
}
string hashText = CryptographicBuffer.EncodeToHexString(hash.GetValueAndReset()).ToUpper();
inputStream.Dispose();
stream.Dispose();

更多详情请参考official sample