Introduction

وقتی یک بخش حقوقی چندین قرارداد PDF دریافت می‌کند، هر بازبین معمولاً رمز عبور خود را برای محافظت از بندهای محرمانه اضافه می‌کند. ترکیب این فایل‌ها در یک بایندر تبدیل به کابوسی می‌شود زیرا رمزهای عبور متفاوت هستند و فایل‌ها نمی‌توانند به‌صورت مستقیم ادغام شوند. رمزگشایی دستی زمان‌بر و مستعد خطا است، به‌ویژه وقتی با ده‌ها PDF سروکار دارید.

Password‑merge یک جریان کاری GroupDocs.Merger برای Java است که PDFهای مختلف را باز می‌کند و نتیجهٔ ادغام‌شده را با یک اعتبار واحد دوباره محافظت می‌کند. این آموزش گام به گام نحوهٔ شناسایی PDFهای محافظت‌شده، باز کردن آن‌ها، ادغام محتوا و به‌صورت اختیاری چرخاندن رمز یکپارچه را نشان می‌دهد.

شما یاد می‌گیرید چگونه API Merger را پیکربندی کنید، جریان‌های بایتی را پردازش کنید و یک PDF ترکیبی امن را در کمتر از ۳۰ خط کد Java تولید کنید.

When should I merge password‑protected PDFs?

ادغام PDFهای محافظت‌شده با رمز عبور زمانی منطقی است که به یک آرشیو واحد و قابل جستجو نیاز داشته باشید که سیاست‌های امنیتی را رعایت کند و در عین حال نیاز به مدیریت چندین رمز عبور را حذف کند. سناریوهای معمول شامل بسته‌های گزارش مالی فصلی، بایندرهای قرارداد برای حسابرسی و پرونده‌های حقوقی است که هر مشارکت‌کننده رمز متفاوتی اعمال کرده است. با باز کردن هر فایل به‌صورت برنامه‌نویسی و اعمال یک رمز یکپارچه، آرشیو را ایمن نگه می‌دارید و فرآیندهای بررسی بعدی را ساده می‌کنید. کل عملیات می‌تواند در یک خط لوله CI خودکار شود و ساعت‌ها کار دستی را صرفه‌جویی کند.

Prerequisites

  • Java 11 یا بالاتر
  • GroupDocs.Merger for Java 24.6+ (temporary license)
  • مجموعه‌ای از فایل‌های PDF که به‌صورت اختیاری هر کدام با رمز عبور خود جفت شده‌اند

نصب کتابخانه از طریق Maven:

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 برمی‌گرداند.
  • همیشه نمونهٔ Merger را برای آزادسازی منابع بومی dispose() کنید.

Step 2 – Unlock each PDF and collect raw bytes

روی یک نقشه (map) که کلید آن مسیر فایل و مقدار آن رمز عبور آن (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 نهایی را با اعتبار ارائه‌شده رمزگذاری می‌کند.
  • تمام عملیات در حافظه انجام می‌شود؛ فقط فایل نهایی روی دیسک نوشته می‌شود.
  • برای آزادسازی دستگیره‌های بومی، Merger را dispose() کنید.

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: Use isDocumentProtected to flag files that may need manual attention. → رمزها را زودتر اعتبارسنجی کنید: از isDocumentProtected برای علامت‌گذاری فایل‌هایی که ممکن است نیاز به مداخله دستی داشته باشند استفاده کنید.
  • Limit memory usage: For large PDFs, stream them to disk instead of keeping all byte arrays in memory. → مصرف حافظه را محدود کنید: برای PDFهای بزرگ، به‌جای نگه‌داشتن تمام آرایه‌های بایت در حافظه، آن‌ها را به دیسک استریم کنید.
  • Dispose objects promptly: The Merger class holds native resources; always call dispose() in a finally block. → به‌سرعت اشیاء را آزاد کنید: کلاس Merger منابع بومی را نگه می‌دارد؛ همیشه در یک بلوک finally dispose() را فراخوانی کنید.
  • 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 برای یک پیاده‌سازی آماده به اجرا بررسی کنید.

Additional Resources