Вступ
Коли юридичний відділ отримує кілька PDF‑документів з контрактами, кожен рецензент часто додає власний пароль для захисту конфіденційних пунктів. Об’єднання цих файлів в один том стає справжнім кошмаром, бо паролі різні і файли не можна з’єднати безпосередньо. Ручне розшифрування займає багато часу і схильне до помилок, особливо коли мова йде про десятки PDF‑файлів.
Password‑merge – це робочий процес GroupDocs.Merger для Java, який розблоковує різнорідні PDF‑файли та повторно захищає результат об’єднання одним спільним паролем. У цьому підручнику розглядається виявлення захищених PDF, їх розблокування, об’єднання вмісту та, за потреби, ротація єдиного пароля.
Ви дізнаєтеся, як налаштувати API Merger, працювати з потоками байтів і створювати захищений комбінований PDF у менш ніж 30 рядках коду Java.
Коли варто об’єднувати 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();
}
}
Key points:
LoadOptionscarries a known password; if none is provided the file is opened normally.isPasswordSet()reports true for both owner and user passwords.- Always dispose the
Mergerinstance to free native resources.
Крок 2 – Розблокування кожного PDF та збір необроблених байтів
Ітеруйте по мапі, де ключ – шлях до файлу, а значення – його пароль (null, якщо пароля немає). Метод повертає список масивів байтів, що представляють розблоковані 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;
}
Key points:
removePassword()strips the existing protection.- The decrypted content is written to a
ByteArrayOutputStreamfor in‑memory handling. - Files without a password are read directly to keep the flow simple.
Крок 3 – Об’єднання розблокованих PDF та застосування єдиного пароля
Створіть Merger з першого потоку PDF, потім приєднайте решту потоків. Нарешті захистіть комбінований документ за допомогою 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);
}
Key points:
addPasswordencrypts the final PDF with the supplied credential.- All operations happen in memory; only the final file is written to disk.
- Dispose the
Mergerto release native handles.
Крок 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);
}
Key points:
- Load the protected PDF with the current password.
updatePasswordreplaces it with the new credential.- This operation is fast because it does not re‑process the PDF content.
Реальний приклад використання
Я зіткнувся з цим, коли консолідував п’ять інвесторських контрактів, кожен з яких мав інший пароль рецензента. Використовуючи наведені вище кроки, я розблокував усі файли, об’єднав їх в один том і застосував один пароль, що відповідав нашій корпоративній політиці. Весь процес зайняв менше двох хвилин на стандартному ноутбуці.
Кращі практики
- Validate passwords early: Use
isDocumentProtectedto flag files that may need manual attention. - Limit memory usage: For large PDFs, stream them to disk instead of keeping all byte arrays in memory.
- Dispose objects promptly: The Merger class holds native resources; always call
dispose()in afinallyblock. - Use a temporary license only for development; obtain a production license before release.
Висновок
GroupDocs.Merger for