2016-08-12 33 views
0

我必須在這裏犯一個愚蠢的錯誤,因爲這應該正在工作。我在考慮這個文件是否保持開放或者是什麼,這讓我瘋狂。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;你看到的是從你調用此函數的最後一次.. –

回答

2

無關緊要地將輸出文件對象作爲上下文管理器打開。如果您明確地手動關閉文件對象,則無關緊要。

這是因爲當你的手一個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

1

我建議你添加一個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

在這種情況下,「開放式」構造是一個錯誤的保證,當超出範圍時文件將被關閉。如果其中一位蟒蛇大師可以證實這很棒。 –