🌊

System.IO.HashingのxxHashを使っててハマった話

2024/04/15に公開

概要

ファイルコピーにおけるチェックサムとしてMD5を使っていたのですが、xxHashを使ったらどれくらい速くなるのか試してみたくなり使ってみた所、進捗をレポートする処理でハッシュが不正になってしまう現象に遭遇しました。色々調査した結果改善できたので共有します。

結論

https://stackoverflow.com/questions/75750329/how-to-calculate-the-progress-of-hashing-system-io-hashing
やりたかったのはこれなのですがコメントを見て「読み込みデータだけじゃなくてバッファを丸ごと送っている事が原因」である事が分かったので、AsSpanを使って読み込んだデータだけ送るようにすれば直りました。

private byte[] GetXxHash3(string filename)
{
    var hashAlgorithm = new XxHash3();
    var bufferSize = 1024 * 1024; // 1MB
    var buffer = new byte[bufferSize];
    using (var entryStream = System.IO.File.OpenRead(filename))
    {
        var bytesRead = entryStream.Read(buffer, 0, buffer.Length);
        while (bytesRead > 0)
        {
            // AsSpanを使って読み込んだデータだけAppendする。
            hashAlgorithm.Append(buffer.AsSpan(0, bytesRead));
            // 元々は以下のように書いてた。
            // hashAlgorithm.Append(buffer);
            // 処理を以下に書く。
        }
    }
    return hashAlgorithm.GetHashAndReset());
}

経緯

元々MD5でチェックサムを実装していたのはTransformBlockTransformFinalBlockを使って進捗レポートを送りながらハッシュを計算していました。ですがチェックサムでMD5を使うのは重いので、高速なxxHashに切り替えたらどれくらい速くなるのかが気になってやってみようと思いました。
xxHashのOSSをいろいろ探っていたのですが、.NET Platform Extensionsで公式から配布されている事が分かり、導入してみました。NuGetで配布されています。
https://www.nuget.org/packages/System.IO.Hashing/
netstandard2.0で実装されているのが素晴らしい!!!

これを導入して色々使い方を調べたら、どうやらAppendメソッドを使えば進捗レポートを送りつつハッシュ計算ができるのでは?と思って作っていました。
ただこれだと全然違うハッシュが生成されてしまうので更に調べまくった結果、バッファをそのままAppendメソッドに送ってはいけないという事にたどり着きました。

Discussion