filecmp.cmp() 忽略不同的 os.stat() 签名?

7 投票
2 回答
3666 浏览
提问于 2025-04-17 05:50

Python 2 的文档中关于 filecmp() 这样写道:

除非给定 shallow 参数并且它为假,否则具有相同 os.stat() 签名的文件会被认为是相等的。

这听起来像是说,除了 os.stat() 签名不同之外的两个文件会被认为是不相等的,但实际上似乎并不是这样,下面的代码片段就说明了这一点:

import filecmp
import os
import shutil
import time

with open('test_file_1', 'w') as f:
    f.write('file contents')
shutil.copy('test_file_1', 'test_file_2')
time.sleep(5)  # pause to get a different time-stamp
os.utime('test_file_2', None)  # change copied file's time-stamp

print 'test_file_1:', os.stat('test_file_1')
print 'test_file_2:', os.stat('test_file_2')
print 'filecmp.cmp():', filecmp.cmp('test_file_1', 'test_file_2')

输出:

test_file_1: nt.stat_result(st_mode=33206, st_ino=0L, st_dev=0, st_nlink=0,
  st_uid=0, st_gid=0, st_size=13L, st_atime=1320719522L, st_mtime=1320720444L, 
  st_ctime=1320719522L)
test_file_2: nt.stat_result(st_mode=33206, st_ino=0L, st_dev=0, st_nlink=0, 
  st_uid=0, st_gid=0, st_size=13L, st_atime=1320720504L, st_mtime=1320720504L, 
  st_ctime=1320719539L)
filecmp.cmp(): True

如你所见,这两个文件的时间戳——st_atimest_mtimest_ctime——显然不相同,但 filecmp.cmp() 却显示这两个文件是相同的。我是不是理解错了,还是 filecmp.cmp() 的实现或文档有问题?

更新

Python 3 的 文档 已经重新表述,现在的内容是这样的,我认为这是一个改进,因为它更好地暗示了即使 shallow 为真,时间戳不同的文件仍然可能被认为是相等的。

如果 shallow 为真,具有相同 os.stat() 签名的文件会被认为是相等的。否则,将比较文件的内容。

顺便说一下,我觉得如果直接说成这样会更好:

如果 shallow 为真,只有在 os.stat() 签名不相等时才比较文件内容。

2 个回答

1

看起来自己动手做是得到想要结果的唯一办法。如果文档能写得更清楚一些,让普通读者也能明白这一点,那就太好了。

这是我现在正在使用的函数:

def cmp_stat_weak(a, b):
    sa = os.stat(a)
    sb = os.stat(b)
    return (sa.st_size == sb.st_size and sa.st_mtime == sb.st_mtime)
8

你对文档的理解有些偏差。第二行说:

除非给定了shallow并且它是假的,否则具有相同os.stat()信息的文件被认为是相等的。

具有相同os.stat()信息的文件被认为是相等的,但反过来说并不成立:具有不同os.stat()信息的文件不一定被认为是不相等的。实际上,它们可能是不相等的,这种情况下就需要比较文件的实际内容。因为文件内容被发现是相同的,所以filecmp.cmp()返回True

根据第三条,一旦确定文件是相等的,它会把这个结果缓存起来,如果你再次要求比较同样的文件,只要这些文件的os.stat信息没有变化,它就不会再去读取文件内容了。

撰写回答