介紹
當法務部門收到多份合約 PDF 時,每位審閱者通常會為保護機密條款而設定自己的密碼。將這些檔案合併成一本資料夾變成了噩夢,因為密碼各不相同,檔案無法直接合併。手動解密既耗時又容易出錯,尤其是面對數十份 PDF 時。
Password‑merge 是一個 GroupDocs.Merger 的 Java 工作流程,能解鎖各種受保護的 PDF,並以單一憑證重新保護合併後的結果。本教學將說明如何偵測受保護的 PDF、解鎖它們、合併內容,並可選擇性地旋轉統一密碼。
您將學會如何設定 Merger API、處理位元串流,並在不到 30 行 Java 程式碼內產生安全的合併 PDF。
什麼時候應該合併受密碼保護的 PDF?
只要需要一個單一、可搜尋的檔案庫,同時遵守安全政策並消除管理多個密碼的負擔,就應該合併受密碼保護的 PDF。典型情境包括季報財務報告套件、審計用的合約資料夾,以及每位貢獻者都設定了不同密碼的法律案件檔案。透過程式化解鎖每個檔案並套用統一密碼,您既能保持檔案安全,又能簡化後續審閱流程。整個作業甚至可以在 CI 流水線中自動化,節省大量手動工作時間。
前置條件
- Java 11 或更新版本
- GroupDocs.Merger for Java 24.6+(temporary license)
- 一組 PDF 檔案,每個檔案可選擇性搭配其密碼
透過 Maven 安裝函式庫:
mvn dependency:copy -Dartifact=com.groupdocs:groupdocs-merger:24.6
步驟 1 – 偵測 PDF 是否受密碼保護
在嘗試解鎖檔案之前,先檢查它是否真的設定了密碼。這可避免不必要的處理,並讓您記錄哪些檔案需要憑證。
// Returns true if the PDF at `path` has an owner or user password
public boolean isDocumentProtected(String path, String password) {
Merger merger;
if (password == null || password.isEmpty()) {
merger = new Merger(path);
} else {
merger = new Merger(path, new LoadOptions(password));
}
try {
return merger.isPasswordSet();
} finally {
merger.dispose();
}
}
重點說明:
LoadOptions會攜帶已知的密碼;若未提供則正常開啟檔案。isPasswordSet()會對擁有者密碼與使用者密碼皆回傳 true。- 必須在
finally區塊中釋放Merger實例,以釋放本機資源。
步驟 2 – 解鎖每個 PDF 並收集原始位元組
遍歷一個 Map,其中鍵為檔案路徑,值為其密碼(若無則為 null)。此方法會回傳一個 List<byte[]>,代表已解鎖的 PDF。
public List<byte[]> unlockAll(Map<String, String> sources) throws IOException {
List<byte[]> unlocked = new ArrayList<>();
for (Map.Entry<String, String> e : sources.entrySet()) {
String path = e.getKey();
String password = e.getValue();
System.out.println("Unlocking (credentials=" +
(password != null ? "yes" : "no") + "): " + path);
if (password == null || password.isEmpty()) {
unlocked.add(Files.readAllBytes(Paths.get(path)));
} else {
LoadOptions opts = new LoadOptions(password);
ByteArrayOutputStream buf = new ByteArrayOutputStream();
Merger m = new Merger(path, opts);
try {
m.removePassword();
m.save(buf);
} finally {
m.dispose();
}
unlocked.add(buf.toByteArray());
}
}
return unlocked;
}
重點說明:
removePassword()會移除現有的保護。- 解密後的內容寫入
ByteArrayOutputStream,以便於記憶體內處理。 - 沒有密碼的檔案直接讀取,以保持流程簡潔。
步驟 3 – 合併已解鎖的 PDF 並套用統一密碼
從第一個 PDF 串流建立 Merger,然後加入其餘串流。最後使用 AddPasswordOptions 為合併文件加密。
public void mergeAndProtect(List<byte[]> unlockedPdfs,
String unifiedPassword,
String outputPath) {
InputStream first = new ByteArrayInputStream(unlockedPdfs.get(0));
Merger merger = new Merger(first);
try {
for (int i = 1; i < unlockedPdfs.size(); i++) {
merger.join(new ByteArrayInputStream(unlockedPdfs.get(i)));
}
merger.addPassword(new AddPasswordOptions(unifiedPassword));
merger.save(outputPath);
} finally {
merger.dispose();
}
System.out.println("Merged output: " + new File(outputPath).getAbsolutePath());
System.out.println("Unified password: " + unifiedPassword);
}
重點說明:
addPassword會使用提供的憑證加密最終 PDF。- 所有操作皆在記憶體中完成,僅在最後寫入磁碟。
- 記得釋放
Merger以釋放本機句柄。
步驟 4 – 旋轉已受保護 PDF 的密碼(可選)
如果貴組織要求定期更換密碼,您可以在不重新合併來源檔案的情況下更新憑證。
public void rotateUnifiedPassword(String path,
String oldPassword,
String newPassword,
String outputPath) {
Merger merger = new Merger(path, new LoadOptions(oldPassword));
try {
merger.updatePassword(new UpdatePasswordOptions(newPassword));
merger.save(outputPath);
} finally {
merger.dispose();
}
System.out.println("Rotated output: " + new File(outputPath).getAbsolutePath());
System.out.println("New password: " + newPassword);
}
重點說明:
- 使用目前的密碼載入受保護的 PDF。
updatePassword會以新憑證取代舊密碼。- 此操作速度快,因為不會重新處理 PDF 內容。
真實案例
我在整合五份投資人合約時遇到此問題,這些合約各自有不同的審閱者密碼。依照上述步驟,我解鎖了所有檔案,將它們合併成一本資料夾,並套用符合公司政策的單一密碼。整個流程在普通筆記型電腦上不到兩分鐘即可完成。
最佳實踐
- 提前驗證密碼:使用
isDocumentProtected標記可能需要人工處理的檔案。 - 限制記憶體使用:對於大型 PDF,請改為串流至磁碟,而非將所有位元組陣列保留在記憶體中。
- 即時釋放物件:
Merger類別持有本機資源;務必在finally區塊中呼叫dispose()。 - 僅在開發時使用臨時授權;正式發佈前請取得正式授權。
結論
GroupDocs.Merger for Java 提供了簡潔的 API,讓您能解鎖、合併並重新保護 PDF 集合。遵循四個步驟——偵測保護、解鎖、以統一密碼合併,以及(可選)旋轉密碼——即可在不需人工介入的情況下自動產生安全的 PDF 資料夾。
後續步驟:
- 探索其他選項,例如在合併後設定 PDF 中繼資料(documentation)。
- 了解如何在保留書籤的同時合併 PDF(API reference)。
- 前往 GitHub 查看完整範例專案,以取得即時可執行的實作。