介紹

當法務部門收到多份合約 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 查看完整範例專案,以取得即時可執行的實作。

其他資源