检查文件是否相等

5

在Python中,检查两个文件是否相等最优雅的方式是什么?使用校验和?比较字节?考虑到文件大小不会超过100-200 MB。

6个回答

9

有趣的模块,但它提供的比问题所要求的少:“如果[文件] 看起来 相等,则返回True,否则返回False”。我理解这意味着比较是近似的。了解它的近似程度将会很有趣。此外,我无法找到如何使用“许多不同的方式进行比较,并具有不同的权衡”的方法:您能详细说明吗? - Eric O. Lebigot
使用 hashlib 获取 MD5 也是“近似的”。确保的唯一方法是进行逐字节比较。通过将 False 传递到 shallow 参数,filecmp 支持此操作。 - wump

6
使用hashlib获取每个文件的MD5值,并比较结果。
#! /bin/env python
import hashlib
def filemd5(filename, block_size=2**20):
    f = open(filename)
    md5 = hashlib.md5()
    while True:
        data = f.read(block_size)
        if not data:
            break
        md5.update(data)
    f.close()
    return md5.digest()

if __name__ == "__main__":
    a = filemd5('/home/neo/todo')
    b = filemd5('/home/neo/todo2')
    print(a == b)

更新:从Python 2.1开始,有一个filecmp模块可以满足您的需求,并且还有比较目录的方法。 我之前并不知道这个模块,我也在学习Python :-)

>>> import filecmp
>>> filecmp.cmp('undoc.rst', 'undoc.rst')
True
>>> filecmp.cmp('undoc.rst', 'index.rst')
False

进行MD5哈希的目的是什么?为什么不直接逐块读取两个文件,直到出现不同的块?这将跳过MD5计算阶段,并且可以抵御(尽管不太可能发生)哈希冲突。 - Eric O. Lebigot
2
@EOL 你说得很有道理,那也可以。我唯一看到的优势是,通过存储哈希值+文件修改日期,并在将来再次使用这些预先计算的值。 - invert
如果你想比较文件的内容,而不是仅仅比较元数据,你需要在filecmp.cmp函数的第三个参数中传入False。filecmp.cmp('undoc.rst', 'index.rst', False) - undefined

4

好的,这可能需要两个不同的回答。

如果您有许多文件需要比较,请使用校验和,并为每个文件缓存校验和。为确保准确性,请在此之后逐字节比较匹配的文件。

如果您只有两个文件,请直接进行字节比较,因为您必须读取文件才能计算校验和。

在两种情况下,都可以使用文件大小作为早期检查不等式的方法。


即使在比较多个文件时,校验和也可能会适得其反。如果您只想检查 a == b == c == d,那么我不认为它有意义。如果您想要像 e in (a, b, c, d) 这样的东西,并且您随后想要使用 e、f、g 等进行操作,那么我认为校验和开始变得划算了。 - aaronasterling
1
嗯,比较多个文件最常见的情况是查找重复项。至少我很少见到需要确保一些文件都是相同的情况。 - Joey

1

在尝试其他解决方案之前,您可能想要对两个文件执行os.path.getsize(...)操作。

如果大小不同,则无需比较字节或计算校验和。

当然,这仅适用于文件大小不固定的情况。

示例:

def foo(f1, f2):
    if not os.path.getsize(f1) == os.path.getsize(f2):
        return False # Or similar

    ... # Checksumming / byte-comparing / whatever

-2

我会使用MD5(例如)进行校验和,而不是字节比较加日期检查,并根据您的需求进行名称检查。


2
一个文件的日期与其内容有什么关系? - Joey
校验和是一个好的解决方案,我同意,但你说的“检查日期”是什么意思? - illegal-immigrant
2
你不是必须读取两个文件才能获取它们的校验和吗?如果是这样,那么我认为校验和只会增加冲突的风险。编辑:除非你想像Joey刚才在回答中所说的那样比较多个文件。 - aaronasterling
UPS... @taras.roshko 对,日期不太有用。 - SubniC

-2

那么使用 cmp 呢?

import commands
status, output = commands.getstatusoutput("/usr/bin/cmp file1 file2")
if (status == 0):
  print "files are same"
elif (status == 1):
  print "files differ"
else:
  print "uh oh!"

1
祝你在Windows系统上好运;-) - Joey
1
不是跨平台的解决方案... - illegal-immigrant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接