更快的MD5替代方案?

时间:2008-11-13 23:24:06

标签: c# md5 hash

我正在开发一个搜索整个驱动​​器以查找给定文件的程序。目前,我为已知文件计算MD5哈希,然后递归扫描所有文件,寻找匹配。

唯一的问题是MD5在大文件上的速度非常慢。是否有更快的替代方案,我可以使用,同时保留非常小的误报可能性?

所有代码都在C#中。

谢谢。

更新

我已经读过,即使是MD5也可以非常快,磁盘I / O应该是限制因素。这让我相信我的代码可能不是最佳的。这种方法有什么问题吗?

        MD5 md5 = MD5.Create();
        StringBuilder sb = new StringBuilder();
        try
        {
            using (FileStream fs = File.Open(fileName, FileMode.Open, FileAccess.Read))
            {
                foreach (byte b in md5.ComputeHash(fs))
                    sb.Append(b.ToString("X2"));
            }
            return sb.ToString();
        }
        catch (Exception)
        {
            return "";
        }

6 个答案:

答案 0 :(得分:44)

我希望您只在文件大小匹配时才检查MD5匹配。

另一个优化是对第一个1K(或其他一些任意但很小的数字)进行快速校验和,并在处理整个文件之前确保这些匹配。

当然,所有这些都假设您只是在寻找特定文件的匹配/不匹配决策。

答案 1 :(得分:9)

无论加密要求如何,都存在哈希冲突的可能性,因此不能使用散列函数保证两个文件是相同的。

我曾经写过类似的代码,我首先通过索引所有文件来快速运行,并丢弃任何不同大小的代码。然后对剩余的条目执行快速哈希比较(在每个文件的一部分上)(比较该步骤的字节被证明不太有用 - 许多文件类型具有在文件的开头具有相同字节的公共头部)。然后使用MD5检查在此阶段之后留下的任何文件,如果MD5匹配,则最后对整个文件进行字节比较,以确保内容相同。

答案 2 :(得分:6)

首先考虑一下你的瓶颈是什么:哈希函数本身还是磁盘访问速度?如果您受磁盘限制,更改散列算法将不会给您带来太多帮助。从你的描述中我暗示你总是扫描整个磁盘以找到匹配 - 考虑首先构建索引然后只匹配给定的散列与索引,这将更快。

答案 3 :(得分:5)

只是线性读取文件?读取整个文件,计算md5哈希,然后比较哈希值似乎没有意义。

按顺序读取文件,一次几个字节,允许您在读取后丢弃绝大多数文件,比如4个字节。并且您将节省计算散列函数的所有处理开销,这些函数在您的情况下不会为您提供任何内容。

如果你已经有驱动器中所有文件的哈希值,那么比较它们是有意义的,但如果你必须动态计算它们,那么哈希似乎没有任何优势

我在这里遗漏了什么吗?在这种情况下,哈希会给你带来什么?

答案 4 :(得分:5)

使用MD5比较文件有一个小问题:已知的文件对不同相同 MD5。

这意味着您可以使用MD5来判断文件是否不同(如果MD5不同,文件必须不同),但是您无法使用MD5来判断文件是否为等于(如果文件相同,则MD5必须相同,但如果MD5相等,则文件可能相等或不相等)。

你应该使用尚未被破坏的哈希函数(如SHA-1),或者(如提到的@SoapBox)仅使用MD5作为查找候选者以进行更深入比较的快速方法。

参考文献:

答案 5 :(得分:0)

使用MD5CryptoServiceProvider和BufferedStream

        using (FileStream stream = File.OpenRead(filePath))
        {
            using (var bufferedStream = new BufferedStream(stream, 1024 * 32))
            {
                var sha = new MD5CryptoServiceProvider();
                byte[] checksum = sha.ComputeHash(bufferedStream);
                return BitConverter.ToString(checksum).Replace("-", String.Empty);
            }
        }