【问题标题】:Why is filecmp.cmp being inconsistent?为什么 filecmp.cmp 不一致?
【发布时间】:2017-03-26 03:04:35
【问题描述】:

这个问题是关于 Python 2.7.1 中的filecmp module。据我所知,这两个调用是相同的(Windows,因此大小写差异无关紧要)。一个返回True,另一个返回False

>>> filecmp.cmp(r'h:\dcim\112_1029\imgp7258.dng', r'd:\pictures\2016\112_1029\imgp7258.dng', False)
True
>>> filecmp.cmp('h:\\dcim\\112_1029\\IMGP7258.DNG', 'd:\\pictures\\2016\\112_1029\\IMGP7258.DNG', False)
False

h: 是 SD 卡,而 d: 是标准硬盘。我已经通过资源管理器将文件从h: 复制到d:,所以它们应该是相同的。为了确定,我什至又做了一次。无论我执行多少次或按什么顺序执行,每次调用的结果都是一致的。

这里还有一些实验只是为了进一步混淆。

>>> f1 = r'h:\dcim\112_1029\imgp7258.dng'
>>> f2 = r'd:\pictures\2016\112_1029\imgp7258.dng'
>>> f3 = 'h:\\dcim\\112_1029\\IMGP7258.DNG'
>>> f4 = 'd:\\pictures\\2016\\112_1029\\IMGP7258.DNG'
>>> f1.upper()==f3.upper()
True
>>> f2.upper()==f4.upper()
True
>>> filecmp.cmp(f1, f2, False)
True
>>> filecmp.cmp(f3, f4, False)
False
>>> filecmp.cmp(f1, f4, False)
True
>>> filecmp.cmp(f3, f2, False)
True

根据评论中的要求,以下是os.stat 对 4 个文件名中的每一个的结果。您可以看到,除了访问和创建时间外,它们是相同的,但对于每个版本的文件名,这些时间都是一致的。

>>> os.stat(f1)
nt.stat_result(st_mode=33206, st_ino=0L, st_dev=0, st_nlink=0, st_uid=0, st_gid=0, st_size=15112724L, st_atime=1490418000L, st_mtime=1477766688L, st_ctime=1477766686L)
>>> os.stat(f2)
nt.stat_result(st_mode=33206, st_ino=0L, st_dev=0, st_nlink=0, st_uid=0, st_gid=0, st_size=15112724L, st_atime=1490488519L, st_mtime=1477766688L, st_ctime=1490488519L)
>>> os.stat(f3)
nt.stat_result(st_mode=33206, st_ino=0L, st_dev=0, st_nlink=0, st_uid=0, st_gid=0, st_size=15112724L, st_atime=1490418000L, st_mtime=1477766688L, st_ctime=1477766686L)
>>> os.stat(f4)
nt.stat_result(st_mode=33206, st_ino=0L, st_dev=0, st_nlink=0, st_uid=0, st_gid=0, st_size=15112724L, st_atime=1490488519L, st_mtime=1477766688L, st_ctime=1490488519L)

我想到的另一个测试:

>>> def hashfile(filename):
    m = hashlib.md5()
    with open(filename, 'rb') as f:
        m.update(f.read())
    return ''.join('%02x' % ord(b) for b in m.digest())

>>> hashfile(f1)
'a0042d8623567bcf429069d17e7c3148'
>>> hashfile(f2)
'a0042d8623567bcf429069d17e7c3148'
>>> hashfile(f3)
'a0042d8623567bcf429069d17e7c3148'
>>> hashfile(f4)
'a0042d8623567bcf429069d17e7c3148'
>>> filecmp.cmp(f1, f2, False)
True
>>> filecmp.cmp(f3, f4, False)
False

【问题讨论】:

  • 我已在 Windows 和 Linux 上使用 Python 2.7 和 3.6 尝试过您的代码,但无法重现您的问题。
  • @Vallentin 它可能与 SD 卡上的文件系统有关,但我真的对可能的原因感到困惑。我向你保证这是真的。
  • 您使用的是哪种类型的 SD 卡?它使用的是哪个文件系统?
  • @Vallentin 或者它可能与 Windows 缓存文件的方式有关。 f3f4 将与 Explorer 用于复制文件的文件名完全匹配,其他文件名因大小写而异。
  • @Vallentin 这是一张格式化为 FAT32 的 Lexar 32GB SDHC 卡。

标签: python windows file compare


【解决方案1】:

documentation for 2.7 没有提及,但documentation for 3.4 包含这个非常重要的说明:

此函数使用缓存来存储过去的比较和结果,如果文件的 os.stat() 信息发生更改,则缓存条目无效。可以使用 clear_cache() 清除整个缓存。

缓存似乎对文件名区分大小写。

在我的例子中,我重新复制了文件,所以os.stat() 信息没有改变(Windows 保留了这些属性)。但是,当我在不同情况下使用文件名进行测试时,我得到了与缓存结果不同的未缓存结果。

按照文档中的建议调用 clear_cache() 是解决我的问题的确切方法。

【讨论】:

  • 哎呀。我花了几天时间研究完全相同的问题,最终找到了这个。对于我们这些由于其他限制而停留在 2.7 的人,除了 clear_cache() 之外还有其他解决方案吗?我目前的后备方案是在检查之前使用时间延迟,或者只是比较哈希并称之为好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-03
  • 2013-03-09
  • 2020-02-29
  • 2014-07-05
  • 2018-08-05
相关资源
最近更新 更多