Watch at Ease看見世界,讀懂生活。

科技 · 實用指南

dircmp.diff_files一直為空?重新整理兩處結果,再檢查全部共同檔案

28項本機檢查說明:clear_cache()、新建預設dircmp與深查diff_files,各自都可能漏掉內容不同的檔案。

原創說明圖:同簽章改寫後,模組比較快取與舊dircmp清單分別保留結果。
原創示意圖:原創說明圖:實測CPython 3.12.14;清除模組快取不會刷新舊物件已算出的清單。 Watch at Ease

dircmp.diff_files為空,不能證明兩個目錄中的檔案位元組相同。在CPython 3.12.14實驗中,我們將一個四位元組檔案由AAAA改成BBBB,並刻意保留大小與修改時間。淺比較與先前快取過的深比較仍回傳True。

清除filecmp模組快取後,新一次深比較回傳False,但舊dircmp物件已算出的空清單沒有更新。對空diff_files清單深比較,實際檢查了零個檔名。修復要分辨這兩處狀態,並依明確規則比較目前全部共同檔案。

1. 分辨兩處保留結果

filecmp.cmp的比較簽章包含檔案類型、大小與修改時間。shallow=True時,相同簽章可以直接被接受,不必讀取位元組。shallow=False跳過此捷徑,但路徑與簽章不變時,文件所述的比較快取仍可能提供先前結果。

dircmp還有另一種生命週期:屬性在首次需要時延遲計算,接著保留在該物件。我們先計算d0.diff_files,再改寫檔案。即使clear_cache()之後新深比較回傳False,d0.diff_files仍是原本空清單;清模組快取沒有重建d0。

2. 用受控改寫重現問題

在自己擁有的新暫存目錄中,兩邊都寫入內容為b"AAAA"的report.bin,並設相同固定修改時間。執行clear_cache()、cmp(a,b,shallow=False),再建立d0=filecmp.dircmp(left,right)並讀取d0.diff_files。初始深比較為True,清單為空。

只把右側改為b"BBBB",再用os.utime還原原mtime。斷言確認類型、大小、mtime簽章相同,而實際位元組不同。預設淺比較回傳True,先前快取的深比較也回傳True。這是刻意保留簽章,不是測量檔案系統時間戳記精度。

3. 重建物件,比較common_files

先停止或隔離寫入者,讓輸入穩定。實測3.12可用:filecmp.clear_cache(); fresh=filecmp.dircmp(left,right,ignore=[],hide=[]); match,mismatch,errors=filecmp.cmpfiles(left,right,fresh.common_files,shallow=False)。明確空過濾清單是小型測試資料的規則,不是通用正式環境建議。

改寫後,match與errors為空,mismatch包含report.bin。相反,把fresh.diff_files傳給cmpfiles會得到三個空清單:新的預設物件仍做淺比較,已漏掉被誤判相同的檔案。內容候選集應取common_files,也要保留left_only、right_only、common_funny與errors,不能只輸出單一成功旗標。

4. 使用新參數前先核對版本

實際3.12.14直譯器對filecmp.dircmp(left,right,shallow=False)拋出TypeError。Python 3.13文件說明此參數自3.13加入;我們沒有執行3.13。相容版本提供公開深比較選項,但不會因此將可變輸入變成原子快照,也不能保證刷新已求值的舊物件。

預設dircmp在不符合中繼資料捷徑時也會讀取內容。最後對照中,兩邊位元組相同、修改時間不同,淺比較仍回傳True。所以淺比較並非任何情況都只看中繼資料,時間戳記不同也不能單獨證明內容不同。

5. 將錯誤與名稱過濾納入結果

missing.bin對照進入cmpfiles的errors,而非mismatch。新增extra.bin後,舊物件已算出的right_only沒有它,新物件則有。另一個在新增前建立、尚未存取清單的dircmp,首次存取時看到了它:建構物件不是快照邊界。

暫存測試中名為.git的普通檔案被預設ignore規則隱藏,使用ignore=[],hide=[]後出現。先決定應用程式要比較哪些名稱。內容差異為空,不能證明名稱、類型、遍歷範圍或權限相同。本實驗只涉及平面普通檔案,未測試遞迴、連結遍歷、特殊檔案或並行改寫。

6. 用獨立位元組檢查完成驗證

本次實際安裝GNU cmp 3.10。對兩個已改寫report.bin執行cmp -s回傳1,獨立確認位元組不同;GNU上游手冊定義0為相同、1為不同、2為執行遇到問題。重新計算的SHA-256也不同。錯誤退出不能當成相同或一般內容差異。

全部28項斷言在CPython 3.12.14/Linux通過。報告保留執行版本、平台、GNU版本、指令碼SHA與結果。正式稽核應從穩定輸入集報告選定名稱範圍、每個共同檔案的結果與未解決錯誤。位元組相等只是內容觀察;真實性、中繼資料相同與寫入期間的一致性需要其他保證。

原創說明圖:空diff_files重查與全部common_files深比較,並列GNU cmp退出碼。
原創示意圖:原創說明圖:檢查全部共同檔案才能發現測試差異;名稱範圍與錯誤仍須另查。 Watch at Ease