مقدمه

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

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

شما یاد می‌گیرید چگونه API Merger را پیکربندی کنید، جریان‌های بایت را پردازش کنید و یک PDF ترکیبی امن را در کمتر از ۳۰ خط کد 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();
    }
}

نکات کلیدی:

  • LoadOptions رمز عبور شناخته‌شده را حمل می‌کند؛ اگر هیچ‌کدام ارائه نشود، فایل به‌صورت معمولی باز می‌شود.
  • isPasswordSet() برای هر دو نوع رمز مالک و کاربر مقدار true برمی‌گرداند.
  • همیشه نمونهٔ Merger را برای آزادسازی منابع بومی dispose() کنید.

گام 2 – باز کردن هر PDF و جمع‌آوری بایت‌های خام

روی یک نقشه (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;
}

نکات کلیدی:

  • removePassword() محافظت موجود را حذف می‌کند.
  • محتویات رمزگشایی‌شده به یک ByteArrayOutputStream نوشته می‌شود تا به‌صورت در‑حافظه مدیریت شود.
  • فایل‌های بدون رمز عبور به‌صورت مستقیم خوانده می‌شوند تا جریان کار ساده بماند.

گام 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);
}

نکات کلیدی:

  • addPassword PDF نهایی را با اعتبار ارائه‌شده رمزگذاری می‌کند.
  • تمام عملیات در حافظه انجام می‌شود؛ فقط فایل نهایی روی دیسک ذخیره می‌شود.
  • برای آزادسازی دستگیره‌های بومی، Merger را dispose() کنید.

گام 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های بزرگ، به‌جای نگه‌داشتن تمام آرایه‌های بایت در حافظه، آن‌ها را به دیسک استریم کنید.
  • **