C# MD5 Hash 在超过 2GB 的文件上不一致

C# MD5 Hash inconsistent on files over 2GB

我正在编写一个 c# 应用程序以使用其 V3 API 下载 Google Drive 文件,并检查 Google 提供的 MD5 哈希以确认下载。一切顺利,应用程序正常运行,除了 当文件大于 2GB 时,我检查 MD5 哈希的失败率为 75% 以上。有些有效,但大多数无效。

如果我使用第 3 方 MD5 实用程序进行检查,它会提供正确的哈希值(与 Google 驱动器相同)。我试过单独下载到我的应用程序(即通过浏览器),以防我的应用程序在下载时做一些奇怪的事情,但在通过我的应用程序检查 md5 哈希时也失败了。所以这显然是我这边发生的事情。

我正在使用 c# System.Security.MD5 库,使用 TransformBlock 和 TransformFinalBlock。我尝试了不同的缓冲区大小,只是为了好玩,但没有运气。我也尝试了完整的文件 - ComputeHash(Stream) - 但这也失败了)。

我唯一能看到的(作为对吸管的完全掌握)是 inputOffset 和 inputCount 参数是 int,如果这些函数有,可以考虑 2GB 限制一个内部的“总文件大小”或类似的,它也是一个 int(32 位符号 - 假设)。

我注意到的另一件事是,进程将每隔 8-25% 暂停一次,没有 CPU、磁盘、RAM、垃圾收集或其他 activity在它继续之前的几分钟。当它是“运行”时,我会看到磁盘、CPU 等,如预期的那样,并且进展相当快。这种暂停似乎并不影响最终哈希是否“成功”,但可能是相关的(我在 2GB 以下的大文件上也看到了它)。

有人知道这是否是个问题吗?我见过几个人就大文件哈希问题提出类似的问题,但答案毫无帮助,哈希 应该 始终相同......是的,他们应该,但它看来他们可能不是。最奇怪的是偶尔会在大文件上使用哈希。

下面是代码的简化(错误检查、进度报告等,为了快速阅读而被删除——是的,我也试过这个简化的代码——同样的问题)。不是最干净的,但它可以工作(除了 >2GB 的文件)。在此先感谢您提供有关此问题的任何建议或知识。

            int buffersize = 65536;
            using (var md5 = MD5.Create())
            {
                using (var stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read, buffersize))
                {
                    var block = new byte[buffersize];
                    int length = 0;
                    Int64 filesize = stream.Length;
                    Int64 bytesread = 0;
                    length = stream.Read(block, 0, buffersize);
                    bytesread += length;
                    while (length == block.Length)
                    {
                        md5.TransformBlock(block, 0, length, null, 0);
                        length = stream.Read(block, 0, buffersize);
                        bytesread += length;
                    }
                    md5.TransformFinalBlock(block, 0, length);
                    bytesread += length;
                }
                var hash = md5.Hash;
                return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant();

完全没有已知的原因,它现在可以工作了。尽我所能猜测(这完全是理论上的,不应该发生),我正在处理应用程序的其他部分,这改变了某些东西的位置以避免出现问题...

它仍会不知何故在这里和那里暂停,但哈希现在可以正确返回(应该匹配的时候匹配,不应该匹配的时候不匹配)。