💡 مثال عملي كامل متاح على GitHub:
compare-encrypted-pdf-and-word-documents-dotnet
الطريقة القديمة كانت مؤلمة
وصلت نسختان من اتفاقية توريد إلى صندوق بريدك. كلاهما محمي بكلمة مرور، كل واحدة بكلمة مرور مختلفة، ويحتاج أحدهم نسخة مُعلَّمة تُظهر ما تم تغييره. مكتبة المقارنة التي تستخدمها تتوقع إدخال نص عادي، لذا يضيف خط أنابيب خطوة: فك تشفير كلا الملفين إلى مجلد مؤقت، مقارنة النسخ النصية، ثم تذكر حذفها. هذا المجلد المؤقت أصبح الآن الحلقة الأضعف في سير عمل موجود خصيصًا لأن المستندات حساسة.
هناك نسخة ثانية من نفس المشكلة يسهل تفويتها. بعض الفرق تتخطى المجلد المؤقت وتفك التشفير في الذاكرة بدلاً من ذلك، مما يحل مسألة التنظيف لكنه لا يحل مسألة الصيغة: واجهة برمجة تطبيقات فك التشفير تختلف حسب الصيغة، لذا دعم جداول البيانات المشفرة بعد ملفات PDF المشفرة يعني تكامل ثاني بدلاً من سطر كود ثاني.
التكلفة ليست في استدعاء فك التشفير نفسه - بل في كل ما يحيط به. يجب كتابة نسخ النص العادي في مكان ما، وتنظيفها في كل مسار خروج بما في ذلك مسارات الفشل، وإبقاؤها بعيدًا عن النسخ الاحتياطية وتفريغ الأعطال. الفرق الناتج بهذه الطريقة يأتي غير محمي بشكل افتراضي، لذا يصبح ناتج مدخلين مشفرين هو الملف الوحيد في السلسلة الذي يمكن لأي شخص فتحه.
التكلفة الحقيقية للتحويل عبر فك التشفير: دليل مؤقت يحتوي على نسخ نصية من مستندات تم تشفيرها لسبب ما، مع تنظيف يجب أن يكون صحيحًا في كل مسار خطأ.
هناك طريقة أفضل
المقارنة المحمية بكلمة مرور هي قدرة من 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 - ويكتب ملف نتيجة واحد مع التغييرات مدمجة داخل النص. كلمات مرور مختلفة عمدًا، لأن هذا هو المكان الذي يختبئ فيه الخطأ الأول.
الخطوة 1 - إعطاء كل مستند خيارات تحميل خاصة به
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 واحد إلى المُنشئ وتوقع أن يغطي الأهداف هو أكثر الطرق شيوعًا للخطأ، وبسبب توقيت الفشل، لا يعلن عن نفسه حيث تبحث عنه.
الخطوة 2 - تحديد ما يحمي النتيجة
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يعلن عن تعداد بنفس الاسم لكن بقيم مختلفة، لذا الاسم المجرد لن يُترجم - يجب تأهيله.
الخطوة 3 - حماية الناتج بكلمة مرور خاصة به
عندما ينتقل الفرق إلى المراجعين الذين لا يجب أن يمتلكوا أي من كلمتي المرور الأصليتين، 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);
كلا الكائنين يُمرَّران إلى نسخة Compare ذات الثلاث معلمات. ضبط SaveOptions.Password بمفرده لا يغيّر شيئًا - قيمة التعداد هي ما يُفعِّل كلمة مرور الجانب الحفظي. النتيجة من هذا الاستدعاء تُفتح بـ 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 |
| الكود المطلوب | مساعد فك تشفير + مقارنة | 4 أسطر |
ميزات المقارنة لا تتغير مع المدخل المشفر. أوضاع العرض، صفحات الملخص واكتشاف الأنماط تتصرف تمامًا كما تفعل مع الملفات النصية، لأن الحماية تُعالج بالكامل في طبقة التحميل.
هذا التجميع هو ما يجعل تغطية الصيغ رخيصة. LoadOptions.Password هو خاصية string عادية، ونفس الخاصية تفتح PDF، DOCX، XLSX و PPTX - كود التحميل في مثال Word أدناه هو حرفيًا ما يستخدمه مثال PDF. فقط فئة الخيارات تتغير، وفقط لأن كل صيغة تكشف عن خيارات عرض مختلفة. إضافة دعم جداول البيانات المشفرة إلى كود يقارن بالفعل ملفات PDF مشفرة لا يكلف شيئًا في مسار التحميل.
مثال واقعي: تعديل العقود بين مكاتب المحاماة
يتلقى فريق قانوني كل مراجعة من الاتفاقية مشفرة، مع تدوير كلمة المرور في كل تبادل حتى لا يكشف تسريب كلمة مرور عن التاريخ الكامل. يحتاج الشريك المراجع إلى مستند مُعلَّم واحد لكل جولة، وتحت قواعد الاحتفاظ لا يجوز أن تبقى النسخة المُعلَّمة غير محمية على مشاركة ملفات.
هناك إعدادان يغطيان ذلك. كل مستند يُفتح بـ LoadOptions الخاص به، لذا لا تحتاج تدوير كلمات المرور إلى معالجة خاصة، وPasswordSaveOption.User يمنح كل فرق موزَّع كلمة مرور خاصة به - كلمة تفتح المقارنة ولا شيء آخر.
// 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يكتب التغييرات التي يقبلها أو يرفضها المراجع داخل Word نفسه. - التحكم في تحميل الموارد الخارجية: احظر أو ضع قائمة بيضاء للمراجع البعيدة التي يحملها المستند، كإجراء أمان إضافي في
LoadOptions. - إنشاء صفحة ملخص:
GenerateSummaryPageيضيف نظرة عامة على التغييرات إلى مستند النتيجة.
الخلاصة
التحويل عبر فك التشفير لم يكن أبدًا عن المقارنة - بل عن مكتبة لا تستطيع قراءة ما لديك. ضبط LoadOptions.Password لكل مستند يزيل المجلد المؤقت، ومسارات التنظيف، والفرق غير المحمي في نهاية السلسلة. ثلاث قرارات هي كل ما يبقى: كلمة مرور لكل مستند، PasswordSaveOption صريحة بدلاً من الافتراضي None، ومعالجة الأخطاء حول Compare حيث يصل الفشل فعليًا.
هل أنت مستعد لأتمتة سير عمل المستندات الخاص بك؟
- جرّب تجربة API المجانية
- استكشف تحميل المستندات المحمية بكلمة مرور
- اقرأ الدليل الكامل لـ مقارنة المستندات المحمية
- اطلع على مشروع العينة على GitHub