دمج ملفات DOCX و XLSX و PDF في ملف موحد — تشغيل تجريبي

الشيء الذي كان يلتهم أيام الجمعة الخاصة بي

كل ظهر جمعة، لمدة عام تقريبًا، كان لدي طقوس صغيرة متكررة. كان العقد يصل كثلاث ملفات — الاتفاقية الرئيسية في Word، ملحق التسعير في Excel، ورقة شروط الشريك كملف PDF — وكان عليّ دمجها في ملف PDF واحد نظيف. لا شيء صعب. افتح Word، صدّر إلى PDF. افتح Excel، صدّر إلى PDF. افتح تطبيق دمج PDF مجاني، اسحب الثلاث ملفات، تحقق من الترتيب، احفظ.

كان يستغرق ذلك حوالي ثماني دقائق. اضرب ذلك في خمسة عشر عقدًا في الأسبوع وستفقد ساعتين بسبب تحريك الفأرة. والأسوأ، كل بضعة أسابيع كان أحدهم يرسل ملفًا بملحق في الصفحة الأولى لأن أسماء الملفات تُرتب أبجديًا في تطبيق الدمج.

إذا كان هذا مألوفًا لك، فإن بقية هذه المشاركة هي بعد الظهر الذي استبدلت فيه الطقوس بالكود أخيرًا.

التكلفة الحقيقية ليست الوقت — إنها العقدة الواحدة من كل خمسين التي تكون الصفحات فيها بترتيب خاطئ ولا يلاحظ أحد ذلك حتى يوقع العميل على النسخة الخاطئة.

ما أردت فعلاً

ليس “خط أنابيب مستندات فاخرة”. فقط ثلاثة أشياء:

  1. إعطاء طريقة قائمة من الملفات (أي مزيج من DOCX و XLSX و PDF) والحصول على ملف PDF واحد في المقابل.
  2. توجيه نفس المنطق إلى مجلد وجعله يحدد قائمة الملفات بنفسه.
  3. استخراج نطاق صفحات من الملف الموحد دون إعادة دمج كامل.

هذا هو كل العمل. إذا لم تستطع المكتبة تنفيذ هذه الثلاثة بنظافة، فأنا لا أريد أن أعرف ذلك.

الإعداد

  • .NET 6.0 أو أحدث
  • GroupDocs.Merger for .NET 24.10+ (احصل على ترخيص مؤقت حتى لا تُرسل علامة مائية تجريبية)
  • مجلد يحتوي على أي مزيج من المستندات التي كنت عادةً تدمجها يدويًا
dotnet add package GroupDocs.Merger

هذا كل شيء بالنسبة للتبعيات. لا محول خارجي، لا تثبيت Office بدون واجهة، ولا مكتبة معالجة PDF إضافية.

الخطوة 1 — جعل المجلد هو المدخل

أبدأ دائمًا من هنا لأن هذه هي نقطة الدخول الواقعية. عمليًا، شيء آخر (معالج رفع، مهمة استلام بريد إلكتروني، تفريغ ليلي من المالية) يضع مجموعة من الملفات في دليل، ويجب على الكود الخاص بي التعامل مع ما يجده.

// Pick up every supported file in the drop folder; the PDF wins
// the tie-break for position 0 so the merger keeps the output
// as a PDF regardless of how files are named.
string[] extensions = { ".pdf", ".docx", ".xlsx" };
var files = Directory.EnumerateFiles(folderPath)
    .Where(f => extensions.Contains(Path.GetExtension(f).ToLowerInvariant()))
    .OrderBy(f => Path.GetExtension(f).ToLowerInvariant() == ".pdf" ? 0 : 1)
    .ThenBy(f => f)
    .ToArray();

if (files.Length == 0)
    throw new InvalidOperationException(
        $"No supported documents found in '{folderPath}'.");

حيلة OrderBy هي الجزء المثير. يختار GroupDocs.Merger تنسيق الإخراج من الملف الأول الذي تفتحه — إذا أعطيتّه DOCX كمستند أساسي، ستحصل على DOCX في النهاية. بما أن خط أنابيبي دائمًا يريد PDF، أضمن أن أي PDF موجود في المجلد يحصل على الموضع 0.

نقطتان تستحقان الذكر:

  • ToLowerInvariant() لأن أحد الشركاء قد يرسل لك يومًا ما REPORT.PDF ومرشح التحويل إلى أحرف صغيرة سيتجاهله صامتًا.
  • ThenBy(f) موجود فقط لجعل الإخراج حتميًا. بدونها، قد تختلف نتيجتا تشغيلين على نفس المجلد حسب حالة نظام الملفات.

الخطوة 2 — عملية الدمج نفسها

بمجرد أن أحصل على قائمة مرتبة من المسارات، يصبح الدمج أقصر من وصفه.

Console.WriteLine($"Primary source: {sourcePaths[0]}");
using var merger = new Merger(sourcePaths[0]);

var joinOptions = new JoinOptions();
for (int i = 1; i < sourcePaths.Length; i++)
{
    Console.WriteLine($"Joining: {sourcePaths[i]}");
    merger.Join(sourcePaths[i], joinOptions);
}

merger.Save(outputPath);
Console.WriteLine($"Unified PDF binder saved to: {Path.GetFullPath(outputPath)}");

بعض الملاحظات من الاستخدام الفعلي:

  • الـ using مهم. يحتفظ Merger بمقابض ملفات على المصادر؛ إذا نسيت إغلاقه سيفشل العامل في مجلد السقوط في النهاية في حذف ملفاته المدخلة.
  • JoinOptions فارغ هنا لأن الإعدادات الافتراضية هي ما أحتاجه 95 % من الوقت. عندما تحتاجها، ستجد هناك نطاقات الصفحات، والدوران، ومواقع الإدراج.
  • عندما يدخل Excel إلى الملف الموحد، يتم تحديد تخطيط الورقة إلى صفحة بناءً على منطقة الطباعة في المصنف المصدر. إذا انتهى بـ XLSX إلى 38 صفحة وأردت ثلاث صفحات فقط، فإن الإصلاح يكون في جدول البيانات، وليس في JoinOptions.

تحقق بسيط أضيفه دائمًا مباشرة بعد الحفظ:

using var verify = new Merger(outputPath);
Console.WriteLine($"Result pages: {verify.GetDocumentInfo().PageCount}");

ثانيتان من الكود أمسكوا أكثر من أخطاء “الملحق المفقود صامتًا” مما فعل أي اختبار كتبته.

الخطوة 3 — استخراج شريحة لاحقًا

الطلب المتكرر الذي أتلقاه في كل مرة: “هل يمكنك إرسال صفحة الغلاف فقط؟” أو “العميل يريد التواقيع فقط.” إعادة بناء الملف الموحد لتسليم صفحتين أمر ساذج — الاستخراج يفعله مباشرة.

using var merger = new Merger(binderPath);
merger.ExtractPages(new ExtractOptions(pages));
merger.Save(outputPath);
Console.WriteLine($"Extracted pages [{string.Join(",", pages)}] to " +
    Path.GetFullPath(outputPath));

pages هو مصفوفة int[] تحتوي أرقام الصفحات (بدءًا من 1) التي تريد الاحتفاظ بها. كل شيء آخر يُحذف. العملية سريعة لأن النتيجة بالفعل PDF — لا جولة تحويل.

قبل vs. بعد، بصراحة

ما كنت أفعله سابقًا مع Merger.Join
زمن كل عقدة 5–10 دقائق من النقرات أقل من 30 ثانية من البداية إلى النهاية
الفشل الشائع صفحات بترتيب خاطئ ولا يلاحظ أحد أي ترتيب يحدده قائمة الملفات، بشكل متكرر
التوسع إلى 100/يوم لا يمكن — تحتاج لتوظيف شخص عامل واحد، غالبًا ما يكون مللًا
الكود الذي تُصانِه صفحة Confluence بعنوان “Binder Process v4” فئة واحدة، ~70 سطر
النتيجة ثلاثة ملفات PDF ودعاء ملف موحد، مع عدد صفحات يمكنك تسجيله

الصف الذي يهمني أكثر هو صف “الفشل”. الدمج اليدوي يفشل بصمت؛ الكود الذي يسجل عدد الصفحات يفشل بصوت عالٍ.

قصة حقيقية من فريق قانوني‑تقني صغير

شركة ناشئة مكوّنة من شخصين كان لديها موظف قانوني يبدأ صباه بتجميع العقود. اتفاقية Word، تسعير Excel، ملحق PDF، تُدمج في تطبيق، تُرفع إلى DocuSign. حوالي ثماني دقائق لكل حزمة، ومع 30 حزمة يوميًا كانت تشكل تقريبًا كل صباحها.

وضعوا طريقة فحص المجلد في خدمة الخلفية التي كانت تراقب بريدهم الوارد. عشرون ثانية لكل حزمة، بالإضافة إلى سطر سجل بعدد الصفحات. انتقل الموظف القانوني إلى مراجعة العقود بدلاً من تجميعها. لم يُرسل أحد ملفًا بترتيب خاطئ مرة أخرى — ليس لأن المكتبة سحرية، بل لأن قائمة الملفات صريحة في الكود ويمكنك مقارنة الاختلافات.

string folder = @"C:\IncomingContracts";
string output = @"C:\Processed\ContractPackage.pdf";

var files = CreatePdfBinderFromFolder(folder, output);
Console.WriteLine($"Package created: {files}");

هذا هو التكامل بالكامل. كل ما هو أمامه (مستمع البريد، مسار التخزين) كان جاهزًا بالفعل.

أشياء لم أحتاجها اليوم لكن قد أحتاجها غدًا

تقدم المكتبة مجموعة من الميزات التي لم أتطرق إليها لأن المقال سيطول. تقريبًا بترتيب ما استخدمته:

  • علامات مائية على الإخراج لكتابة “DRAFT” على النسخ قبل التوقيع.
  • دوران الصفحات للمسحات التي تأتي مائلة.
  • ترتيب صفحات مخصص عندما لا يتطابق ترتيب المصدر مع ترتيب التسليم.
  • تشفير PDF لأي شيء يُرسل إلى طرف خارجي.

كل ذلك موجود خلف نفس واجهة Merger. الوثائق docs تحتوي على القائمة الكاملة — أردت فقط الإشارة إلى أن “الدمج” هو البداية الرخيصة والبقية متاحة عندما تحتاجها.

ما كنت سأقوله لنفسي في الماضي

إذا كنت على وشك كتابة خطوة تحويل DOCX إلى PDF لأن “هذه مجرد طريقة واحدة”، توقف. التحويل هو الجزء الذي يتآكل بصمت — ميزات Office الجديدة، معالجة الصور الممسوحة، الخطوط المدمجة، إلخ. دع شيء آخر يتولى تلك الواجهة، وخصص ظهر الجمعة لشيء لا يتعلق بترتيب أسماء الملفات.

إلى أين تذهب بعد ذلك:

روابط مفيدة