檔案同名不代表同一份:用內容雜湊辨識輸入
客戶先後傳來兩份都叫 `final.pdf` 的文件,哪一份做了翻譯?靠文件名回答這個問題很危險。同名檔案可以內容不同,改過名字的檔案也可能位元組完全相同。內容哈希適合建立版本對應關係,但不應該被賦予它沒有的意義。
同名檔案不一定是同一份,改過名字的檔案也可能內容完全相同。如果團隊靠檔案名稱追蹤翻譯版本,很容易搞錯物件。這篇文章說明如何用內容雜湊為輸入和輸出留下位元組級指紋,以及雜湊能證明什麼、不能證明什麼。
範例使用合成樣本示範處理方法,程式碼只在隔離環境中做過範例檢查,並不代表對所有真實文件或產品效果的保證。處理重要文件前,請先保留原件,並依文中的邊界與驗收項複審。
為什麼檔名不可靠?一句話結論
用內容哈希對應版本,檔案名稱只作參考。下表說明常見情況下該怎麼處理。
| 你的情況 | 推薦做法 | 原因 |
|---|---|---|
兩份文件都叫 final.pdf | 比較 SHA-256 摘要,不比較檔名 | 同名檔案的內容可以不同 |
| 文件被改了名字 | 以摘要確認是否為同一位元組內容 | 名稱不參與位元組摘要 |
| 需確認譯稿對應哪份輸入 | 分別記錄輸入和輸出的摘要 | 輸入與輸出是不同的位元組內容 |
| 文件可能被重新保存或改寫元數據 | 視為新的位元組內容重新記錄 | 元資料或壓縮參數改變會影響哈希 |
為輸入留下位元組指紋
SHA-256 根據檔案位元組計算摘要。大檔案可以分塊讀取,不必一次裝入記憶體。哈希結果與分塊大小無關,分塊只是讀取策略,不是檔案身分的一部分。下面的記憶體流是合成樣本,不包含真實文件。
用同內容、不同切塊驗證實現
import hashlib
from io import BytesIO
def digest(stream, chunk_size=65536):
if type(chunk_size) is not int or chunk_size <= 0:
raise ValueError("positive chunk size required")
h = hashlib.sha256()
while block := stream.read(chunk_size):
h.update(block)
return h.hexdigest()
raw = b"synthetic document version A\n"
a = digest(BytesIO(raw), 3)
assert a == digest(BytesIO(raw), 4096)
assert a == hashlib.sha256(raw).hexdigest()
assert a != digest(BytesIO(raw.replace(b"A", b"B")))
assert digest(BytesIO(b"")) == hashlib.sha256(b"").hexdigest()
try:
digest(BytesIO(raw), 0)
except ValueError:
pass
else:
raise AssertionError("zero chunk must be rejected")
函數從目前流位置開始讀取。正式調用前,應明確流是否位於開頭。如果解析器已經讀過一部分內容,直接計算的結果就不是"整份檔案哈希"。最穩健的做法是單獨開啟唯讀輸入,或在可定位的串流上明確重設後再計算。
位元組相同與內容相同有什麼不同?
雜湊只反映位元組是否一致,不同操作對它的影響各不相同。
| 情況 | 哈希可能怎樣變化 | 如何解釋 |
|---|---|---|
| 只改檔名 | 不變 | 名稱不參與位元組摘要 |
| PDF 元資料被重寫 | 改變 | 頁面看起來相同也可能不同 |
| 重新保存壓縮包 | 改變 | 壓縮參數或時間戳記可影響位元組 |
| 翻譯成另一語言 | 通常改變 | 輸入輸出應分別記錄 |
📊 核心對比
| 判斷方式 | 能說明什麼 | 不能說明什麼 |
|---|---|---|
| 比較檔案名稱 | 只能說明名稱相同 | 內容是否一致 |
| 比較 SHA-256 摘要 | 位元組內容是否完全一致 | 是否有權使用該文件,或是否擁有版權 |
🎯 哪一種做法適合你?
如果你需要確認兩份檔案是否一致
比較 SHA-256 摘要,摘要相同說明位元組內容相同,檔名不作為依據。
如果你需要追蹤譯稿來源
分別記錄輸入摘要和輸出摘要,再關聯語言與術語版本。
如果你打算用哈希判斷檔案權限
不要這樣做。哈希不是权限凭证,需要另外做访问控制。
❓ 常見問題(FAQ)
1. 修改檔案名稱後,雜湊會改變嗎?
不會。名稱不參與位元組摘要,只改檔案名稱的檔案雜湊保持不變。
2. 頁面看起來一樣,哈希就一定一樣嗎?
不一定。 PDF 元資料被重寫時,雜湊可能會改變,即使頁面顯示相同。
3. 能用哈希判斷使用者是否有權利下載檔案嗎?
不能。知道文件摘要不代表有權下載,也不代表擁有版權。
4. 跨租戶去重會有什麼風險?
可能洩漏"某個檔案是否已存在"的訊息,因此快取命中之後仍需做存取控制。
翻譯清單從這裡開始
將文件送入OmniDoc(產品入口)前,記錄輸入摘要; 下載譯稿後,記錄輸出摘要,並關聯語言與術語版本。 之後如果同事反饋“結果不對”,雙方可以先確認檢查的是同一組文件,而不必圍繞多個 final 文件名反覆猜測。
參考資料:Python hashlib。
📝 總結
同名不代表同一份,檔名只能作為參考。用內容雜湊記錄輸入輸出,能讓團隊先對齊文件本身,再討論翻譯結果。


