python - 比较新写入的文件与filecmp.cmp()总是返回False?

问题描述:

我必须在这里犯一个愚蠢的错误,因为这应该正在工作。我在考虑这个文件是否保持开放或者是什么,这让我疯狂。python - 比较新写入的文件与filecmp.cmp()总是返回False?

这是一些回归测试用例,我将脚本的生成输出与模拟文件的生成输出比较为已知的良好输出文件(密钥文件)。

下面是一个简单的例子:

def run_and_compare(self, key_file, out_file, option): 
    print filecmp.cmp(out_file, key_file) # always True (as long as I've run this before, so the out_file exists already) 
    cmd = './analyze_files.py -f option' 
    with open(out_file, 'wb') as out: 
     subprocess.Popen(cmd.split(), stdout=out, stderr=subprocess.PIPE) 
    print filecmp.cmp(out_file, key_file) # always False 
    time.sleep(5) 
    print filecmp.cmp(out_file, key_file) # always True 

我真的不希望保持睡眠测试!我怎样才能确保out文件可以比较而不使用睡眠?我试过使用out.close(),但它不起作用,只要我使用'with'就不需要。我在这里使用python 2.6.4。

+0

'filecomp.cmp()'缓存的结果,所以第一* * TRUE;你看到的是从你调用此函数的最后一次.. –

无关紧要地将输出文件对象作为上下文管理器打开。如果您明确地手动关闭文件对象,则无关紧要。

这是因为当你的手一个Python文件对象subprocess.Popen(),所有从该文件对象需要是文件句柄,您的操作系统使用大约打开文件通信的整数。子进程然后使用os.dup2()将该文件句柄克隆到子进程的STDOUT文件句柄上;这是导致该子进程的输出转到磁盘上指定文件的原因。

由于文件句柄已经失效,关闭原始Python文件对象(和间接原始的OS文件句柄)不会实际上关闭文件,因为第二个文件句柄仍然保持打开。

等待几秒钟后出现您看到文件数据的原因是因为最终您创建的子流程将会完成,并且只有是另一个关闭的文件句柄。

而不是等待几秒钟,等待子使用Popen.communicate() method完成:

p = subprocess.Popen(cmd.split(), stdout=open(out_file, 'wb'), 
        stderr=subprocess.PIPE) 
stdout, stderr = p.communicate() # stdout will always be None 

我内联open()电话,因为没有其他使用该文件对象一旦subprocess.Popen()检索到的文件从它处理。您也可以使用os.open()而不是open()(相同的参数),并安全地创建一个只有文件句柄就足够的Python文件对象。

不要使用p.wait();因为你使用的子进程的STDERR流,你可以死锁的过程中,如果你不读STDERR但子进程写入大量数据给它。你最终会永远等待。

+0

真棒解释 - 谢谢! – user797963

我建议你添加一个wait到您的子进程,等待它完成

with open(out_file, 'wb') as out: 
    p=subprocess.Popen(cmd.split(), stdout=out, stderr=subprocess.PIPE) 
    p.wait() 

如果你不等待,子进程启动后,取得文件out作为输出,并立即返回(开始在后台)。 当你比较两个文件时,其中一个可能是空的,因此是False。

过了一段时间,子进程结束,out不再使用,可能垃圾收集,句柄关闭:你的文件是有效的。 (我不是说这到底是什么是怎么回事,但缺乏p.wait()肯定是这里的问题)

之外,我一直想知道为什么人们运行涉及Python命令的子进程时,它是如此简单导入它们并直接调用它们的功能,从而受益于异常链,唯一的过程,避免所有这些进程间通信问题。

+0

这是正确的缓存;我正在调试,发现输出文件较小(实际上是空的)。如果仍然有数据被写入,那么它的较小的唯一原因是:在这里,由管道。 –

+0

谢谢,总是有道理。我对python比较陌生,但是会直接查看导入命令和调用函数。 – user797963

+0

在这种情况下,“开放式”构造是一个错误的保证,当超出范围时文件将被关闭。如果其中一位蟒蛇大师可以证实这很棒。 –