检查文件是否相同的最快方法是什么?

时间:2009-04-24 05:02:57

标签: language-agnostic file comparison

如果您有1,000,000个源文件,您怀疑它们都是相同的,并且您想比较它们当前禁用的方法来比较这些文件是什么?假设它们是Java文件和平台,其中进行比较并不重要。 cksum让我哭泣。当我的意思相同时,我的意思是完全相同。

更新:我知道生成校验和。差异是可笑的...我想要速度。

更新:不要因为它们是源文件而受到限制。举个例子,你假装了一百万次运行非常稳定的程序。您想要证明所有1,000,000个版本的输出都是相同的。

更新:读取块数而不是字节数? Immediatly扔掉那些?这比找到字节数要快吗?

更新:这与比较两个文件的最快方式有什么不同?

18 个答案:

答案 0 :(得分:23)

我会选择类似cmp程序采用的方法:打开两个文件(比如文件1和文件2),从每个文件中读取一个块,然后逐字节地比较它们。如果它们匹配,则从每个块中读取下一个块,逐个字节地比较它们等。如果到达两个文件的末尾而没有检测到任何差异,请寻找文件1的开头,关闭文件2并打开文件3在它的位置,并重复,直到你检查所有文件。我认为没有办法避免读取所有文件的所有字节,如果它们实际上完全相同,但我认为这种方法是(或接近)检测可能存在的任何差异的最快方法。

OP修改:提升了Mark Bessey

的重要评论

“另一个显而易见的优化,如果文件预计大部分相同,如果它们相对较小,则将其中一个文件完全保留在内存中。这会减少尝试一次读取两个文件的麻烦。 “

答案 1 :(得分:14)

他们的回复中的大多数人都忽略了必须反复比较文件的事实。因此,校验和更快,因为校验和计算一次并存储在内存中(而不是按顺序读取文件n次)。

答案 2 :(得分:7)

假设期望文件将是相同的(听起来就像那个场景),那么处理校验和/哈希是浪费时间 - 它们可能会是相同的而且你会有重新读取文件以获得最终证明(我也假设你要“证明......它们是相同的”,将它们哈希到相同的值是不够好的。)

如果是这种情况,我认为the solution proposed by David非常接近你需要做的事情。可以采取一些措施来优化比较,增加复杂程度:

  • 在进行比较之前检查文件大小是否相同
  • 使用最快的memcmp()(比较单词而不是字节 - 大多数C运行时都应该这样做)
  • 使用多个线程进行内存块比较(最多可达到系统上可用的处理器数量,超过这会导致你的线程互相争斗)
  • 使用重叠/异步I / O来保持I / O通道尽可能繁忙,但也要仔细分析,以便尽可能少地在文件之间进行抖动(如果文件在几个不同的磁盘和I / O之间分配端口,更好)

答案 3 :(得分:6)

更新:不要因为它们是源文件而受到限制。举个例子,你假装了一百万次运行非常稳定的程序。您想证明所有1,000,000个版本的输出都是相同的。

如果您可以控制输出,那么创建文件/输出的程序会动态创建md5并将其嵌入到文件或输出流中,甚至可以通过程序管理输出,该程序会创建md5并存储它以某种方式与数据并排,点是在字节已经在内存中时进行计算。

如果你不能像其他人所说的那样关闭它,检查文件大小然后在相同大小的文件上进行逐字节比较,我不知道任何类型的二进制除法或md5计算是否更好与直接比较相比,你必须触摸每个字节以证明相等,无论你削减它,所以你也可以减少每个字节所需的计算量,并在你发现不匹配时立即获得切断的能力。

如果您计划稍后将这些数据再次与新输出进行比较,那么md5计算将非常有用,但您基本上会回到我第一次尽快计算md5

答案 4 :(得分:2)

最佳算法将取决于重复文件的数量。

假设有一些是相同的,但大多数是不同的,文件很大。

使用简单的文件长度检查过滤掉显然不相同的那些。

从文件中选择随机字节,计算哈希值并进行比较(最小化磁盘搜索)

使用完整文件SHA1。

答案 5 :(得分:2)

有许多程序通常比较一组文件以找到相同的文件。 FDUPES很好:Link。根据输入的确切性质,一百万个文件不是问题。我认为FDUPES需要Linux,但其他平台还有其他此类程序。

我自己尝试编写更快的程序,但除特殊情况外,FDUPES更快。

无论如何,一般的想法是首先检查文件的大小。具有不同大小的文件不能相等,因此您只需要查看具有相同大小的文件组。如果你想要最佳性能,它会变得更复杂:如果文件可能不同,你应该比较文件的小部分,以期尽早发现差异,这样你就不必阅读其余部分了。但是,如果文件可能相同,则可以更快地读取每个文件以计算校验和,因为这样您就可以从磁盘顺序读取而不是在两个或更多文件之间来回跳转。 (这假设是普通磁盘,因此SSD:s可能不同。)

在我的基准测试中,当试图制作更快的程序时(有点令我意外)结果是更快地首先读取每个文件以计算校验和,然后如果校验和相等,则通过读取直接比较文件一个块交替地从每个文件,而不是只是交替读取块没有以前的校验和计算!事实证明,在计算校验和时,Linux将两个文件缓存在主内存中,顺序读取每个文件,然后第二次读取非常快。从交替读取开始时,文件不是(物理上)按顺序读取的。

编辑:

有些人表示意外的结果甚至怀疑,阅读文件的速度比阅读文件一次要快两倍。也许我无法清楚地解释我在做什么。我正在谈论缓存预加载,以便在以后以对物理磁盘驱动器执行缓慢的方式访问它们时将文件放入磁盘缓存中。 Here是一个网页,我试图通过图片,C代码和测量来详细解释。

然而,这与原始问题(最多)具有边际相关性。

答案 6 :(得分:1)

我会运行这样的东西

find -name \*.java -print0 | xargs -0 md5sum | sort

然后查看哪些文件具有不同的MD5总和。这将按校验和对文件进行分组。

如果你愿意,你可以替换sha1sum甚至rmd160的md5sum。

答案 7 :(得分:1)

我不认为散列比逐字节比较更快。逐字节比较可以通过流水线化读取和比较字节来优化一点,也可以在并行线程中比较文件的多个部分。它会是这样的:

  • 检查文件大小是否不同
  • 以异步方式将文件块读入内存
  • 将它们处理为工作线程以进行比较

或者只是并行运行cmp(或等效于您的操作系统)。这可以很容易编写脚本,你仍然可以获得并行性的好处。

答案 8 :(得分:1)

使用cksum并不像md5sum那样可靠。但我会选择最大可靠性,这意味着使用cmp进行逐字节比较。

您必须读取所有检查方法的两个文件中的每个字节,因此您也可以选择最可靠的方法。

作为第一遍,您可以查看目录列表以查看尺寸是否不同。这是一种快速获取不同文件反馈的方法。

答案 9 :(得分:0)

超越比较,同步两个文件夹,超快!我们每天都在使用它。

答案 10 :(得分:0)

我首先要创建一个数据库表,其中包含file_contents的路径名和sha_1列,
所有文件并存储pathName和sha_1,
然后将其存储到数据库中后,
sha_1文件检查数据库中是否存在sha_1,
如果在db中,
输出到该文件已存在且路径名为
的日志 用它做任何事大声笑创建一个符号链接。
上传文件后,请在您的验证中实现它,

答案 11 :(得分:0)

如果要逐个比较文件,请使用ExamDiff。

答案 12 :(得分:0)

在我看来,这是一个文件系统操作。首先,请谨慎选择文件系统。接下来,重复数据删除。然后比较inode。像:

% find / -inum "$(ls -di "./test.file" | grep -E '^[0-9]*')"
<list of identical files provided in a few seconds to a minute>

答案 13 :(得分:0)

使用Bloom Filter的概念。 这里有一个简单的解释:http://crzyjcky.com/2013/01/03/the-magical-bloom-filter/

它给你恒定的比较时间。但是这种方法不能单独使用。 Apache Cassandra和HBase在内部使用这种技术。

它基本上以非常快的方式告诉你文件不相同。如果它说文件是相同的,你必须使用可靠的方法进行另一轮检查。

答案 14 :(得分:0)

我刚刚编写了一个c#app,它可以执行类似于您想要的操作。我的代码是做什么的。

将所有文件的大小全部读入列表或数组。

使用for循环检查这些尺寸是否相同。 如果它们的大小相同,则将一个文件的一个字节与另一个文件的一个字节进行比较。如果两个字节相同,则移动到下一个字节。如果找到差异,则返回文件不同。

如果到达两个文件的末尾,并且最后两个字节相同,则文件必须相同。

我已经尝试过比较文件的MD5哈希值而不是逐字节,我发现这种方法经常会错过相同的文件,但速度要快得多。

答案 15 :(得分:0)

首先比较所有百万的文件长度。如果您有一个便宜的方法,请从最大的文件开始。如果它们全部通过,则使用二进制除法模式比较每个文件;这对于相似但不相同的文件会更快失败。有关此比较方法的信息,请参阅Knuth-Morris-Pratt method

答案 16 :(得分:0)

为什么重新发明轮子?第三方应用怎么样?虽然它没有API,但我不认为你经常把自己置于这种情况。我喜欢这个应用程序doublekiller,只需在开始之前进行备份。 :)这是快速而自由的!

答案 17 :(得分:0)

MD5哈希比比较快,但比正常的CRC检查慢。你必须弄清楚你想要的那种可靠性。