💡 مثال کامل کاری در GitHub موجود است:
compare-encrypted-pdf-and-word-documents-dotnet

روش قدیمی دردسرساز بود

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

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

هزینه عمدتاً در فراخوانی رمزگشایی نیست – بلکه در همه چیزهای اطراف آن است. نسخه‌های متنی ساده باید جایی نوشته شوند، در هر مسیر خروجی (از جمله مسیرهای خطا) پاک‌سازی شوند و از نسخه‌های پشتیبان و کرش‌دمپ‌ها دور نگه داشته شوند. یک diff که به این شکل تولید می‌شود به‌طور پیش‌فرض محافظت نشده است، بنابراین خروجی دو ورودی رمزگذاری‌شده تبدیل به فایلی می‌شود که هر کسی می‌تواند آن را باز کند.

هزینه واقعی دور زدن رمزگشایی: یک پوشهٔ موقت حاوی نسخه‌های متنی ساده اسنادی که به دلیلی رمزگذاری شده‌اند، با پاک‌سازی‌ای که باید در هر مسیر خطا صحیح باشد.

راه بهتر وجود دارد

مقایسهٔ محافظت‌شده با رمز عبور یک قابلیت GroupDocs.Comparison برای .NET است که فایل‌های PDF، DOCX، XLSX و PPTX رمزگذاری‌شده را در محل باز می‌کند و تصمیم می‌گیرد چه رمز عبوری نتیجهٔ مقایسه را محافظت می‌کند. نیازی به مرحلهٔ رمزگشایی، نیازی به واسطهٔ متنی ساده نیست: رمز عبور همراه سند به داخل مقایسه می‌رود، به‌عنوان یک ویژگی در LoadOptions.

قبل از شروع، به موارد زیر نیاز دارید:

  • .NET 8.0 SDK یا بالاتر
  • GroupDocs.Comparison 26.9.0 (مجوز موقت)
  • دو سند رمزگذاری‌شده با قالب یکسان و رمزهای عبور آن‌ها

نصب با یک فرمان:

dotnet add package GroupDocs.Comparison

روش جدید: اسناد رمزگذاری‌شده مستقیماً به مقایسه‌گر

مثال زیر دو PDF رمزگذاری‌شده را مقایسه می‌کند – منبع با 1234 باز می‌شود، هدف با 4321 – و یک فایل نتیجهٔ واحد با تغییرات ادغام‌شده به‌صورت درون‌خطی می‌نویسد. رمزهای عبور متفاوت عمداً انتخاب شده‌اند، زیرا اینجا اولین اشتباه پنهان می‌شود.

گام ۱ - به هر سند LoadOptions مخصوص خود را بدهید

یک Comparer یک منبع و هر تعداد هدف را نگه می‌دارد و هر سند حفاظت خود را دارد. رمز عبور منبع به سازنده می‌رود؛ رمز عبور هر هدف به فراخوانی Add مخصوص خود می‌رود.

// One LoadOptions per document - the constructor's options unlock the
// source only, and never reach the targets.
using var comparer = new Comparer("source.pdf",
    new LoadOptions { Password = "1234" });
comparer.Add("target.pdf", new LoadOptions { Password = "4321" });

این همان جزئیاتی است که مردم را گم می‌کند. پاس دادن یک LoadOptions واحد به سازنده و انتظار اینکه برای اهداف هم اعمال شود، رایج‌ترین راهی است که این مسئله اشتباه می‌شود و به‌دلیل زمان‌بندی خطا، خود را در جایی که به‌دنبال آن می‌گردید، اعلام نمی‌کند.

گام ۲ - تصمیم بگیرید چه چیزی نتیجه را محافظت می‌کند

CompareOptions.PasswordSaveOption حفاظت خروجی را انتخاب می‌کند: None، Source، Target یا User. مقدار پیش‌فرض None است که به‌صورت ساکت دو ورودی رمزگذاری‌شده را به یک نتیجهٔ بدون محافظت تبدیل می‌کند.

// Inline markup, and the result reuses the source document's password.
var options = new PdfCompareOptions
{
    DisplayMode = PdfCompareOptions.ComparisonDisplayMode.Inline,
    PasswordSaveOption = PasswordSaveOption.Source
};

comparer.Compare("Result/1-pdf-inline.pdf", options);

نکات کلیدی:

  • PasswordSaveOption: Source رمز عبور منبع را برای خروجی دوباره استفاده می‌کند. برای صدور رمز جدید، User را همراه با SaveOptions.Password انتخاب کنید.
  • ComparisonDisplayMode: درون PdfCompareOptions قرار دارد و همچنین SideBySide و Interleaved را ارائه می‌دهد. WordCompareOptions یک enum با همان نام ولی مقادیر متفاوت دارد، بنابراین نام ساده کامپایل نمی‌شود – باید آن را به‌صورت کامل بنویسید.

گام ۳ - خروجی را با رمز عبور مخصوص خود محافظت کنید

وقتی diff به بازبینی‌کنندگانی می‌رود که نباید هیچ‌یک از رمزهای عبور اصلی را داشته باشند، PasswordSaveOption.User مقدار را از SaveOptions.Password می‌گیرد به‌جای استفاده مجدد از رمز ورودی.

var compareOptions = new PdfCompareOptions
{
    DisplayMode = PdfCompareOptions.ComparisonDisplayMode.Inline,
    PasswordSaveOption = PasswordSaveOption.User
};
var saveOptions = new SaveOptions { Password = "5678" };

comparer.Compare("Result/4-own-password.pdf", saveOptions, compareOptions);

هر دو شیء به overload سه‌پارامتری Compare می‌روند. تنظیم SaveOptions.Password به‌تنهایی چیزی تغییر نمی‌دهد – مقدار enum است که رمز عبور سمت ذخیره را فعال می‌کند. نتیجهٔ این فراخوانی با 5678 باز می‌شود و 1234 را رد می‌کند.

چرا try/catch دور Comparer رمز عبور اشتباه را نمی‌گیرد؟

چون سازنده هرگز سند را باز نمی‌کند. مسیر را ثبت می‌کند و Add نیز همین‌طور. هر دو سند زمانی که Compare اجرا می‌شود خوانده می‌شوند و در همانجا PasswordProtectedFileException با پیام Password is missing پرتاب می‌شود. یک رمز عبور اشتباه به‌طور یکسان رفتار می‌کند: در زمان ساخت به‌صورت ساکت پذیرفته می‌شود و سپس در Compare رد می‌شود.

بنابراین فراخوانی مقایسه را بپوشانید، نه سازنده. من این را به‌صورت آهسته یافت‌ام، با بسته‌بندی ساخت در یک try و مشاهدهٔ عبور یک فایل رمزگذاری‌شده از آن قبل از اینکه سه خط بعدی خطا بدهد. مخزن هر مرحله را چاپ می‌کند که ترتیب را در اولین نگاه واضح می‌سازد:

using var comparer = new Comparer("source.pdf");   // succeeds
comparer.Add("target.pdf");                        // succeeds
comparer.Compare("Result/unreachable.pdf");        // throws here

مقایسهٔ کنار‌به‌کنار: قبل vs. بعد

قبل (ابتدا رمزگشایی) بعد (GroupDocs.Comparison)
مراحل خط لوله رمزگشایی هر دو، مقایسه، حذف نسخه‌های موقت مقایسه
متن ساده روی دیسک دو نسخه، پاک‌سازی در هر مسیر خطا هیچ‌کدام
محافظت نتیجه یک مرحلهٔ رمزگذاری مجدد جداگانه یک مقدار PasswordSaveOption
پوشش قالب ابزارهای رمزگشایی مخصوص هر قالب یک LoadOptions.Password برای PDF، DOCX، XLSX، PPTX
کد مورد نیاز کمکی برای رمزگشایی به‌علاوه مقایسه ۴ خط

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

این لایه‌بندی است که پوشش قالب را ارزان می‌کند. LoadOptions.Password یک ویژگی string ساده است و همان ویژگی PDF، DOCX، XLSX و PPTX را باز می‌کند – کد بارگذاری در مثال Word که در ادامه می‌آید، حرف به حرف همان چیزی است که مثال‌های PDF استفاده می‌کنند. فقط کلاس گزینه‌ها تغییر می‌کند و فقط به این دلیل که هر قالب گزینه‌های رندرینگ متفاوتی ارائه می‌دهد. افزودن پشتیبانی از صفحه‌گستردهٔ رمزگذاری‌شده به کدی که قبلاً PDFهای رمزگذاری‌شده را مقایسه می‌کند، هیچ هزینه‌ای در مسیر بارگذاری اضافه نمی‌کند.

مثال واقعی: اصلاح قرارداد بین شرکت‌های حقوقی

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

دو تنظیمات این نیاز را پوشش می‌دهند. هر سند با LoadOptions مخصوص خود قفل‌گشایی می‌شود، بنابراین چرخش رمزها نیازی به مدیریت خاص ندارد و PasswordSaveOption.User به هر diff توزیع‌شده یک رمز عبور اختصاصی می‌دهد – رمزی که فقط مقایسه را باز می‌کند و هیچ چیز دیگری نیست.

// Word revisions, so the reviewing partner can accept or reject each edit.
var options = new WordCompareOptions
{
    DisplayMode = WordCompareOptions.ComparisonDisplayMode.Revisions,
    PasswordSaveOption = PasswordSaveOption.Source
};

using var comparer = new Comparer("round3.docx",
    new LoadOptions { Password = "1234" });
comparer.Add("round4.docx", new LoadOptions { Password = "4321" });
comparer.Compare("Result/redline.docx", options);

دیگر کارهایی که می‌توانید با GroupDocs.Comparison انجام دهید

  • مقایسهٔ بیش از دو سند محافظت‌شده: چند هدف رمزگذاری‌شده را به یک مقایسه اضافه کنید، برای قالب‌های Word و ارائه.
  • تولید بازبینی‌های بومی Word: WordCompareOptions.ComparisonDisplayMode.Revisions تغییرات را به‌صورت بازبینی‌هایی می‌نویسد که مرورگر می‌تواند بپذیرد یا رد کند.
  • کنترل بارگذاری منابع خارجی: مسدود یا فهرست سفید کردن مراجع راه دوری که سند حمل می‌کند، یک محافظت دیگر LoadOptions.
  • تولید صفحهٔ خلاصه: GenerateSummaryPage یک نمای کلی از تغییرات را به سند نتیجه اضافه می‌کند.

نتیجه‌گیری

دور زدن رمزگشایی هرگز دربارهٔ مقایسه نبود – بلکه دربارهٔ کتابخانه‌ای بود که نمی‌توانست آنچه را که دارید بخواند. تنظیم LoadOptions.Password برای هر سند پوشهٔ موقت، مسیرهای پاک‌سازی و diff بدون محافظت در انتهای زنجیره را حذف می‌کند. سه تصمیم باقی می‌ماند: یک رمز عبور برای هر سند، یک PasswordSaveOption صریح به‌جای مقدار پیش‌فرض None، و مدیریت خطا دور Compare که در آنجا خطا واقعاً رخ می‌دهد.

آماده‌اید جریان کاری اسناد خود را خودکار کنید؟

منابع تکمیلی