为什么filecmp.cmp不一致?

时间:2017-03-26 03:04:36

标签: python windows file compare

这个问题与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

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

>>> 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

1 个答案:

答案 0 :(得分:0)

documentation for 2.7没有提到它,但documentation for 3.4包含了这个非常重要的注释:

  

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

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

在我的情况下,我重新复制了文件,因此import javax.swing.BoxLayout; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.SwingUtilities; public class MultiLineOptionPane { private JPanel pane; public static void main(String[] args) { SwingUtilities.invokeLater(new MultiLineOptionPane()::createAndShowGui); } public void createAndShowGui() { pane = new JPanel(); pane.setLayout(new BoxLayout(pane, BoxLayout.PAGE_AXIS)); StringBuilder sb = new StringBuilder(); //This object will be used to concatenate in the next for loop for (int i = 0; i < 500; i++) { //Sample for loop if ((i) % 10 == 0) { //Every 10 numbers we restart the StringBuilder pane.add(new JLabel(sb.toString())); //We add a new JLabel to the JPanel with the contents of the StringBuilder sb.delete(0, sb.length()); //We restart the StringBuilder } else { sb.append(i); //We append the current number to the StringBuilder sb.append(" "); //We append a space after the number } } pane.add(new JLabel(sb.toString())); //We add the last line of numbers in the StringBuilder to the pane JOptionPane.showMessageDialog(new JFrame(), pane, "Numbers", JOptionPane.PLAIN_MESSAGE); //We display the message } } 信息没有改变(Windows保留了这些属性)。但是,当我在不同的情况下使用文件名进行测试时,我获得了与缓存结果不同的未缓存结果。

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