Introduction
เมื่อแผนกกฎหมายได้รับ PDF สัญญาหลายไฟล์ แต่ละผู้ตรวจสอบมักจะเพิ่มรหัสผ่านของตนเองเพื่อปกป้องข้อกำหนดที่เป็นความลับ การรวมไฟล์เหล่านี้เป็นแฟ้มเดียวกลายเป็นเรื่องน่าสะพรึงกลัว เพราะรหัสผ่านต่างกันและไฟล์ไม่สามารถรวมโดยตรงได้ การถอดรหัสด้วยมือใช้เวลานานและเสี่ยงต่อข้อผิดพลาด โดยเฉพาะเมื่อต้องจัดการกับหลายสิบไฟล์ PDF
Password‑merge คือเวิร์กโฟลว์ของ GroupDocs.Merger สำหรับ Java ที่ปลดล็อก PDF ที่มีความหลากหลายและปกป้องผลลัพธ์ที่รวมแล้วด้วยข้อมูลรับรองเดียวกัน บทเรียนนี้จะอธิบายขั้นตอนการตรวจจับ PDF ที่มีการป้องกัน การปลดล็อก การรวมเนื้อหา และการหมุนรหัสผ่านที่รวมไว้ (ถ้าต้องการ)
คุณจะได้เรียนรู้วิธีกำหนดค่า Merger API การประมวลผลสตรีมไบต์ และการสร้าง PDF ที่รวมกันอย่างปลอดภัยด้วยโค้ด Java ไม่เกิน 30 บรรทัด
When should I merge password‑protected PDFs?
การรวม PDF ที่มีรหัสผ่านเป็นประโยชน์เมื่อคุณต้องการคลังข้อมูลเดียวที่สามารถค้นหาได้และสอดคล้องกับนโยบายความปลอดภัย พร้อมกับลดภาระการจัดการรหัสผ่านหลายชุด สถานการณ์ทั่วไปได้แก่ ชุดรายงานการเงินรายไตรมาส, แฟ้มสัญญาสำหรับการตรวจสอบ, และไฟล์คดีทางกฎหมายที่ผู้ร่วมทำแต่ละคนใช้รหัสผ่านต่างกัน โดยการปลดล็อกแต่ละไฟล์ด้วยโปรแกรมและใส่รหัสผ่านเดียว คุณจะรักษาความปลอดภัยของคลังข้อมูลและทำให้กระบวนการตรวจสอบต่อไปง่ายขึ้น การดำเนินการทั้งหมดสามารถทำอัตโนมัติใน CI pipeline เพื่อประหยัดเวลาทำงานหลายชั่วโมง
Prerequisites
- Java 11 หรือใหม่กว่า
- GroupDocs.Merger for Java 24.6+ (temporary license)
- ชุดไฟล์ PDF, แต่ละไฟล์อาจมีรหัสผ่านที่สอดคล้องกันหรือไม่มี
mvn dependency:copy -Dartifact=com.groupdocs:groupdocs-merger:24.6
Step 1 – Detect if a PDF is password‑protected
ก่อนที่จะพยายามปลดล็อกไฟล์ ให้ตรวจสอบว่ามีรหัสผ่านหรือไม่ การทำเช่นนี้ช่วยหลีกเลี่ยงการประมวลผลที่ไม่จำเป็นและทำให้คุณบันทึกไฟล์ที่ต้องการข้อมูลรับรอง
// 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:
LoadOptionsถือรหัสผ่านที่ทราบไว้; หากไม่มีการระบุไฟล์จะเปิดตามปกติisPasswordSet()คืนค่า true ทั้งสำหรับรหัสผ่านเจ้าของและผู้ใช้- ควรทำการ dispose อินสแตนซ์
Mergerเสมอเพื่อปล่อยทรัพยากรเนทีฟ
Step 2 – Unlock each PDF and collect raw bytes
วนลูปผ่านแผนที่ที่คีย์เป็นเส้นทางไฟล์และค่าคือรหัสผ่านของไฟล์นั้น (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()ลบการป้องกันที่มีอยู่- เนื้อหาที่ถอดรหัสจะถูกเขียนลงใน
ByteArrayOutputStreamเพื่อการจัดการในหน่วยความจำ - ไฟล์ที่ไม่มีรหัสผ่านจะถูกอ่านโดยตรงเพื่อให้กระบวนการง่ายขึ้น
Step 3 – Merge the unlocked PDFs and apply a unified password
สร้าง 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:
addPasswordเข้ารหัส PDF สุดท้ายด้วยข้อมูลรับรองที่ระบุ- ทุกการดำเนินการเกิดขึ้นในหน่วยความจำ; มีเพียงไฟล์สุดท้ายที่บันทึกลงดิสก์
- ทำการ dispose
Mergerเพื่อปล่อยแฮนด์เดิลเนทีฟ
Step 4 – Rotate the password on an already‑protected PDF (optional)
หากองค์กรของคุณกำหนดให้ต้องหมุนรหัสผ่านเป็นระยะ คุณสามารถอัปเดตข้อมูลรับรองได้โดยไม่ต้องรวมไฟล์ต้นฉบับใหม่
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:
- โหลด PDF ที่ป้องกันด้วยรหัสผ่านปัจจุบัน
updatePasswordแทนที่ด้วยข้อมูลรับรองใหม่- การดำเนินการนี้เร็วเพราะไม่ต้องประมวลผลเนื้อหา PDF ใหม่
Real‑World Application
ฉันเจอปัญหานี้เมื่อต้องรวมสัญญานักลงทุนห้าฉบับที่แต่ละฉบับมีรหัสผ่านผู้ตรวจสอบต่างกัน ด้วยขั้นตอนข้างต้น ฉันปลดล็อกไฟล์ทั้งหมด รวมเป็นแฟ้มเดียว และใส่รหัสผ่านเดียวที่สอดคล้องกับนโยบายของบริษัท กระบวนการทั้งหมดใช้เวลาน้อยกว่าสองนาทีบนแล็ปท็อปมาตรฐาน
Best Practices
- Validate passwords early: ใช้
isDocumentProtectedเพื่อระบุไฟล์ที่อาจต้องการการตรวจสอบด้วยมือ - Limit memory usage: สำหรับ PDF ขนาดใหญ่ ให้สตรีมไปยังดิสก์แทนการเก็บอาร์เรย์ไบต์ทั้งหมดในหน่วยความจำ
- Dispose objects promptly: คลาส Merger ถือทรัพยากรเนทีฟ; ควรเรียก
dispose()ในบล็อกfinallyเสมอ - Use a temporary license only for development; obtain a production license before release.
Conclusion
GroupDocs.Merger for Java ให้ API ที่เรียบง่ายสำหรับการปลดล็อก, การรวม, และการปกป้อง PDF อีกครั้ง การทำตามสี่ขั้นตอน—ตรวจจับการป้องกัน, ปลดล็อก, รวมด้วยรหัสผ่านเดียว, และอาจหมุนรหัสผ่านนั้น—คุณสามารถอัตโนมัติการสร้างแฟ้ม PDF ที่ปลอดภัยโดยไม่ต้องทำด้วยมือ
Next steps:
- สำรวจตัวเลือกเพิ่มเติม เช่น การตั้งค่าเมตาดาต้า PDF หลังการรวม (documentation).
- เรียนรู้วิธีรวม PDF พร้อมคงบู๊กมาร์ก (API reference).
- ดูโครงการตัวอย่างเต็มบน GitHub สำหรับการใช้งานที่พร้อมรัน