为何Python的filecmp在浅模式下将修改时间不同的文件判定为相同?
这个问题挺有意思的——按预期filecmp.cmp(shallow=True)应该通过文件的元数据(权限、大小、修改时间)判断差异,但你遇到了修改时间不同却返回相同的矛盾结果。结合Python 3.5在Windows 10下的特性,我梳理了几个核心原因和验证方法:
可能的原因
1. 浮点数精度的隐形问题
Windows NTFS文件系统的时间精度是100纳秒,但Python的float类型只有约15-17位十进制精度。当文件修改时间的差异极小(比如小于1毫秒),转换为浮点数的st_mtime可能会因为舍入误差被视为相等,导致_sig打印看起来有差异,但实际比较时返回True。
2. filecmp缓存机制的干扰
虽然你调用了filecmp.clear_cache(),但如果你的脚本是在交互环境中多次运行,或者之前执行过shallow=False的文件比较,缓存可能没有完全失效。filecmp.cmp会优先读取缓存结果,而不是重新计算元数据差异。
3. Python 3.5的filecmp模块bug
Python 3.5在Windows平台上的文件系统相关模块存在一些已知问题,比如对文件时间戳的处理逻辑不完善。后续的Python 3.6+版本修复了不少这类底层bug,升级版本大概率能解决问题。
4. 文件系统的时间精度限制
如果你的文件存储在FAT32格式的分区上,它的文件时间精度只有2秒。即使你看到的修改时间不同,只要差异小于2秒,st_mtime就会被截断为相同的整数值,导致元数据比较认为文件相同。
验证步骤
你可以通过以下代码进一步定位问题:
精确打印修改时间:查看
st_mtime的完整精度,确认是否真的存在差异stat1 = os.stat(links) stat2 = os.stat(rechts) print(f"文件1修改时间(精确到纳秒级): {stat1.st_mtime:.9f}") print(f"文件2修改时间(精确到纳秒级): {stat2.st_mtime:.9f}")手动拆解元数据比较:逐个验证
_sig的三个元素是否真的相等sig1 = filecmp._sig(stat1) sig2 = filecmp._sig(stat2) print(f"权限是否相同: {sig1[0] == sig2[0]}") print(f"文件大小是否相同: {sig1[1] == sig2[1]}") print(f"修改时间是否相同: {sig1[2] == sig2[2]}")绕过缓存的手动比较:直接实现
shallow=True的逻辑,对比filecmp.cmp的结果def manual_shallow_cmp(f1, f2): s1 = os.stat(f1) s2 = os.stat(f2) return s1.st_mode == s2.st_mode and s1.st_size == s2.st_size and s1.st_mtime == s2.st_mtime print("手动元数据比较结果:", manual_shallow_cmp(links, rechts))
如果手动比较的结果和filecmp.cmp不同,基本可以确定是缓存或模块bug导致的,此时升级Python版本到3.6+是最直接的解决方案。
内容的提问来源于stack exchange,提问作者Übend

