💡 完整可運作的範例可在 GitHub 上取得: compare-encrypted-pdf-and-word-documents-dotnet
舊方式很痛苦
兩版供應協議的修訂稿抵達你的收件匣。兩者皆受密碼保護,且各自使用不同的密碼,且有人需要一份標註了變更的副本。你手上的比較函式庫只接受純文字輸入,因此流程必須多加一步:將兩個檔案解密至暫存資料夾、比較純文字副本,然後記得將它們刪除。這個暫存資料夾成了工作流程中最薄弱的環節,而這個工作流程之所以存在,正是因為文件本身具有敏感性。
還有第二種相同問題的變體更容易被忽視。某些團隊跳過暫存資料夾,改為在記憶體中解密,這解決了清理的問題,但沒有解決格式的問題:解密 API 依格式而異,因此在支援加密 PDF 之後再支援加密試算表,就意味著需要第二套整合,而不是只多寫一行程式碼。
成本主要不在解密呼叫本身,而在其周圍的一切。必須將純文字副本寫入某處,並在每條退出路徑(包括失敗路徑)上清理,且必須避免備份與崩潰轉儲中留下痕跡。以此方式產生的差異檔預設也是未受保護的,因此兩個加密輸入的結果會變成鏈中唯一一個任何人都能開啟的檔案。
解密繞道的真正成本:一個暫存目錄保存了因某種原因被加密的文件的純文字副本,且必須在每條錯誤路徑上正確清理。
有更好的方法
受密碼保護的比較是 GroupDocs.Comparison 在 .NET 上的功能,能直接在原位開啟加密的 PDF、DOCX、XLSX 與 PPTX 檔案,並決定使用哪個密碼保護比較結果。無需解密步驟,無需純文字中介:密碼會隨文件一起傳入比較本身,作為 LoadOptions 的屬性。
在開始之前,你需要:
- .NET 8.0 SDK 或更新版本
- GroupDocs.Comparison 26.9.0(臨時授權)
- 兩個相同格式的加密文件,以及它們的密碼
使用一條指令安裝:
dotnet add package GroupDocs.Comparison
新方法:直接將加密文件送入比較器
以下範例比較兩個加密的 PDF——來源使用 1234 開啟,目標使用 4321 開啟——並寫入一個單一的結果檔,將變更內嵌合併。特意使用不同的密碼,因為錯誤往往隱藏在此處。
步驟 1 - 為每個文件提供自己的 LoadOptions
Comparer 持有一個來源與任意數量的目標,每個文件都攜帶自己的保護。來源的密碼傳入建構子;每個目標的密碼則傳入各自的 Add 呼叫。
// One LoadOptions per document - the constructor's options unlock the
// source only, and never reach the targets.
using var comparer = new Comparer("source.pdf",
new LoadOptions { Password = "1234" });
comparer.Add("target.pdf", new LoadOptions { Password = "4321" });
這是讓人卡住的細節。將單一 LoadOptions 傳給建構子並期望它涵蓋所有目標,是最常見的錯誤做法,而因為失敗的時機,錯誤不會在你檢查的地方顯示。
步驟 2 - 決定結果的保護方式
CompareOptions.PasswordSaveOption 決定輸出的保護方式:None、Source、Target 或 User。預設為 None,會悄悄將兩個加密輸入變成一個未受保護的結果。
// Inline markup, and the result reuses the source document's password.
var options = new PdfCompareOptions
{
DisplayMode = PdfCompareOptions.ComparisonDisplayMode.Inline,
PasswordSaveOption = PasswordSaveOption.Source
};
comparer.Compare("Result/1-pdf-inline.pdf", options);
要點:
- PasswordSaveOption:
Source會在輸出上重用來源的密碼。若想使用新密碼,請搭配SaveOptions.Password並選擇User。 - ComparisonDisplayMode:此列舉位於
PdfCompareOptions之下,亦提供SideBySide與Interleaved。WordCompareOptions另有同名列舉但值不同,直接使用名稱會編譯失敗——請加上限定名稱。
步驟 3 - 為輸出設定自己的密碼
當差異檔要交給不應持有任何原始密碼的審閱者時,PasswordSaveOption.User 會改用 SaveOptions.Password 的值,而不是重用輸入的密碼。
var compareOptions = new PdfCompareOptions
{
DisplayMode = PdfCompareOptions.ComparisonDisplayMode.Inline,
PasswordSaveOption = PasswordSaveOption.User
};
var saveOptions = new SaveOptions { Password = "5678" };
comparer.Compare("Result/4-own-password.pdf", saveOptions, compareOptions);
兩個物件都傳給三參數的 Compare 重載。僅設定 SaveOptions.Password 本身不會產生任何變化——必須搭配列舉值才會啟用儲存端的密碼。此呼叫的結果以 5678 開啟,且拒絕 1234。
為什麼在 Comparer 周圍的 try/catch 捕獲不到錯誤的密碼?
因為建構子從不開啟文件。它只記錄路徑,Add 也是如此。兩個文件會在 Compare 執行時被讀取,屆時會拋出 PasswordProtectedFileException,訊息為 Password is missing。錯誤的密碼行為完全相同:建構時靜默接受,之後在 Compare 時被拒絕。
因此要保護比較呼叫,而不是建構子。我是以較慢的方式發現這點:把建構包在 try 中,觀察加密文件先順利通過建構,卻在三行之後的 Compare 失敗。程式庫會印出每個階段,使第一次閱讀時就能看出順序:
using var comparer = new Comparer("source.pdf"); // succeeds
comparer.Add("target.pdf"); // succeeds
comparer.Compare("Result/unreachable.pdf"); // throws here
並排比較:前後對照
| 之前(先解密) | 之後(GroupDocs.Comparison) | |
|---|---|---|
| 流程步驟 | 解密兩個文件,進行比較,刪除暫存副本 | 比較 |
| 磁碟上的明文 | 兩個副本,於每個錯誤路徑清理 | 無 |
| 結果保護 | 單獨的重新加密步驟 | 單一 PasswordSaveOption 設定值 |
| 格式支援 | 每種格式的解密工具 | 對 PDF、DOCX、XLSX、PPTX 使用單一 LoadOptions.Password |
| 所需程式碼 | 解密輔助程式加比較 | 4 行 |
比較功能在加密輸入時不會改變。顯示模式、摘要頁面與樣式偵測的行為與純文字檔完全相同,因為保護完全在載入層處理。
正是這層抽象讓格式支援變得廉價。LoadOptions.Password 只是一個普通的 string 屬性,同一屬性即可解鎖 PDF、DOCX、XLSX 與 PPTX——下面的 Word 範例的載入程式碼與 PDF 範例逐字相同。唯一改變的是選項類別,因為每種格式會暴露不同的渲染選項。為已支援加密 PDF 的程式碼加入加密試算表支援,載入路徑上幾乎不會產生額外成本。
真實案例:律師事務所之間的合約修訂
法律團隊收到每次修訂的合約皆為加密,且每次交換都會更換密碼,以防洩漏的密碼暴露整個歷史。審閱合夥人需要每輪一份標註過的文件,且依據保存規範,標註過的副本不得未受保護地放在檔案分享區。
兩個設定即可解決此需求。每個文件都由自己的 LoadOptions 解鎖,密碼輪換不需額外處理;PasswordSaveOption.User 為每個分發的差異檔設定自己的密碼——只解鎖比較結果,其他地方無法使用。
// Word revisions, so the reviewing partner can accept or reject each edit.
var options = new WordCompareOptions
{
DisplayMode = WordCompareOptions.ComparisonDisplayMode.Revisions,
PasswordSaveOption = PasswordSaveOption.Source
};
using var comparer = new Comparer("round3.docx",
new LoadOptions { Password = "1234" });
comparer.Add("round4.docx", new LoadOptions { Password = "4321" });
comparer.Compare("Result/redline.docx", options);
GroupDocs.Comparison 還能做什麼?
- 比較超過兩個受保護的文件:將多個加密目標加入同一次比較,支援 Word 與簡報格式。
- 產生原生 Word 修訂:
WordCompareOptions.ComparisonDisplayMode.Revisions會在 Word 中寫入審閱者可接受或拒絕的變更。 - 控制外部資源載入:封鎖或白名單文件所攜帶的遠端參考,另提供
LoadOptions保障。 - 產生摘要頁:
GenerateSummaryPage會在結果文件中加入變更概覽。
結論
解密繞道從來不是比較本身的問題——而是函式庫無法讀取你手上的檔案。為每個文件設定 LoadOptions.Password 後,即可省去暫存資料夾、清理路徑,以及鏈最後的未受保護差異檔。剩下的只有三個決策:每文件一個密碼、使用明確的 PasswordSaveOption(而非預設的 None),以及在 Compare 周圍處理錯誤,因為失敗會在那裡發生。
準備好自動化你的文件工作流程了嗎?
- 嘗試免費 API 試用
- 探索載入受密碼保護的文件
- 閱讀完整的受保護文件比較指南
- 查看 GitHub 上的範例專案