يمكن لملف PDF أن يحمل ملفات أخرى داخله. يمكن أن يكون محفظة تجمع العقود وجداول البيانات، أو تقريرًا مع البيانات المصدرية المرفقة. عندما تقوم باستخراج تلك الملفات في الكود، تريد حفظ كل ملف بالاسم الذي أعطاه المؤلف، وليس attachment1.bin. يوضح هذا البرنامج التعليمي كيفية استخراج الملفات المدمجة من ملف PDF بأسمائها الأصلية في C# باستخدام Aspose.PDF for .NET. ستقوم بفتح ملف PDF، وتكرار الملفات المدمجة فيه، وتحديد اسم كل ملف باستخدام FileSpecification.GetFileName، وكتابة المحتويات إلى مجلد.

أين يخزن ملف PDF اسم الملف المضمّن

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

Aspose.PDF for .NET يوفر الخاصية FileSpecification.GetFileName للتعامل مع هذا. يقوم بحل الاسم من الاسم Unicode أو اسم الملف العادي أو مفتاح المجموعة، أيًا كان متاحًا، لذا لا يزال بإمكانك الحصول على اسم قابل للاستخدام عندما يكون الاسم Unicode مفقودًا. يمكنك تمرير اسم احتياطي للملفات التي لا تملك اسمًا على الإطلاق. يتحكم المعامل الثاني الاختياري فيما إذا كان يُسمح باسم فارغ عندما لا يتوفر اسم ملف. ستحصل على استدعاء واحد بدلاً من كتابة منطقك الخاص لقراءة قواميس PDF.

ملاحظة: الأمثلة في هذه المقالة تستخدم فقط معامل الاحتياطي.

Document.EmbeddedFiles يحتفظ بالمرفقات على مستوى المستند، والتي تشمل الملفات في مجموعة PDF. الملفات المرفقة بصفحة معينة عبر ملاحظة مرفق ملف (عادةً ما تُظهر كأيقونة مشبك ورق) تُخزن على الملاحظة بدلاً من ذلك؛ استخراج الملفات المرفقة بالصفحات يغطي ذلك.

استخدام Aspose.PDF لاستخراج الملفات المدمجة من ملف PDF

Install-Package Aspose.PDF

أو باستخدام .NET CLI:

dotnet add package Aspose.PDF
  • ملف PDF يحتوي على ملفات مدمجة. يستخدم المثال محفظة تسمى PDFPortfolio.pdf.

بدون ترخيص، يعمل Aspose.PDF في وضع التقييم. لاختبار بدون قيود التقييم، اطلب رخصة مؤقتة مجانية.

استخراج كل ملف مضمّن باسمه الأصلي

تقوم الطريقة التالية بفتح ملف PDF، وتحفظ كل ملف مضمّن في مجلد الإخراج تحت اسمه المستخرج، وتطبع مسار كل ملف يتم كتابته.

using System;
using System.IO;
using Aspose.Pdf;

public static class EmbeddedFileExtractor
{
    public static void ExtractEmbeddedFiles(string inputPdf, string outputDir)
    {
        Directory.CreateDirectory(outputDir);

using (var document = new Document(inputPdf))
        {
            foreach (FileSpecification fileSpec in document.EmbeddedFiles)
            {
                // Resolve the stored name, then keep only the file name part.
                string fileName = Path.GetFileName(fileSpec.GetFileName("attachment.bin"));
                string outputPath = Path.Combine(outputDir, fileName);

using (var output = new FileStream(outputPath, FileMode.Create))
                {
                    fileSpec.Contents.CopyTo(output);
                }

Console.WriteLine($"Saved: {outputPath}");
            }
        }
    }
}

استدعِه مع مسار ملف PDF والمجلد الذي تريد وضع الملفات فيه:

EmbeddedFileExtractor.ExtractEmbeddedFiles("PDFPortfolio.pdf", "ExtractedFiles");

ما يفعله كل خطوة

افتح المستند. new Document(inputPdf) يقوم بتحميل ملف PDF. كتلة using تُحرّر مقبض الملف عندما تنتهي المعالجة، حتى إذا تم رمي استثناء.

التكرار عبر المرفقات. document.EmbeddedFiles تُرجع كائن FileSpecification واحد لكل ملف مضمّن على مستوى المستند.

استرجاع الاسم. fileSpec.GetFileName("attachment.bin") يُعيد الاسم المخزن، أو attachment.bin إذا لم يوفر PDF أي اسم. اختر قيمة احتياطية منطقية لتطبيقك.

إزالة مقاطع المجلد. يمكن أن يتضمن اسم مخزن مسارًا مثل reports/2026/q3.xlsx، أو قيمة مُصنّعة مثل ..\..\startup.bat. تمرير النتيجة عبر Path.GetFileName يقللها إلى q3.xlsx أو startup.bat، لذا لا يمكن كتابة الملف خارج outputDir. احتفظ بهذه الخطوة حتى إذا كنت تثق في ملفات PDF التي تعالجها اليوم.

اكتب المحتويات. fileSpec.Contents هو تدفق لبيانات الملف المضمّن. CopyTo يكتبها إلى الملف الجديد دون أي تحويل.

النتيجة المتوقعة

يحتوي مجلد الإخراج على ملف واحد لكل مرفق على مستوى المستند، مسمى كما تم تخزينه في ملف PDF. بالنسبة لمحفظة تحتوي على جدول بيانات ومستند Word، يبدو إخراج وحدة التحكم مشابهًا لهذا:

Saved: ExtractedFiles\budget-2026.xlsx
Saved: ExtractedFiles\service-agreement.docx

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

معالجة الأسماء المكررة وغير الآمنة

المثال الأساسي يحتوي على ثلاث نقاط ضعف ستواجهها مع ملفات PDF الواقعية:

  • يمكن لمرفقين مشاركة اسم، وFileMode.Create يستبدل الأول بصمت. يحدث هذا أيضًا عندما لا يحتوي عدة مرفقات على اسم وتعود جميعها إلى attachment.bin.
  • الاسم الذي يكون صالحًا على نظام تشغيل واحد قد يحتوي على أحرف غير صالحة على نظام آخر، مثل : على Windows.
  • الاسم المخزن الذي ينتهي بفاصل مسار يترك Path.GetFileName بسلسلة فارغة.

يتعامل هذا المساعد مع الثلاثة جميعًا. فهو يستبدل الأحرف غير الصالحة، ويعود إلى قيمة افتراضية عندما يكون الاسم فارغًا، ويضيف عدادًا عندما يكون الملف موجودًا بالفعل:

private static string GetSafeOutputPath(string outputDir, string resolvedName, string fallbackName)
{
    string fileName = Path.GetFileName(resolvedName);

foreach (char c in Path.GetInvalidFileNameChars())
    {
        fileName = fileName.Replace(c, '_');
    }

if (string.IsNullOrWhiteSpace(fileName))
    {
        fileName = fallbackName;
    }

string baseName = Path.GetFileNameWithoutExtension(fileName);
    string extension = Path.GetExtension(fileName);
    string outputPath = Path.Combine(outputDir, fileName);

int counter = 1;
    while (File.Exists(outputPath))
    {
        outputPath = Path.Combine(outputDir, $"{baseName} ({counter}){extension}");
        counter++;
    }

return outputPath;
}

في حلقة الاستخراج، استبدل السطرين اللذين يبنيان fileName و outputPath بـ:

string outputPath = GetSafeOutputPath(outputDir, fileSpec.GetFileName("attachment.bin"), "attachment.bin");

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

استخراج الملفات المرفقة بالصفحات

إذا كان EmbeddedFiles فارغًا ولكنك ترى أيقونة مشبك الورق في عارض PDF، فمن المحتمل أن الملف مرفق عبر ملاحظة إرفاق ملف على صفحة. تحتوي الملاحظة على FileSpecification الخاص بها في الخاصية File، لذا يتم تطبيق نفس حل الاسم ونفس المساعد. تقوم هذه الطريقة بفحص كل صفحة وحفظ كل ملف مرفق إلى مجلد الإخراج:

using Aspose.Pdf.Annotations;

public static void ExtractPageAttachments(string inputPdf, string outputDir)
{
    Directory.CreateDirectory(outputDir);

using (var document = new Document(inputPdf))
    {
        foreach (Page page in document.Pages)
        {
            foreach (Annotation annotation in page.Annotations)
            {
                if (annotation is FileAttachmentAnnotation attachment && attachment.File != null)
                {
                    string outputPath = GetSafeOutputPath(outputDir, attachment.File.GetFileName("attachment.bin"), "attachment.bin");

using (var output = new FileStream(outputPath, FileMode.Create))
                    {
                        attachment.File.Contents.CopyTo(output);
                    }

Console.WriteLine($"Saved: {outputPath}");
                }
            }
        }
    }
}

لجمع كل المرفقات في ملف PDF، شغّل الطريقتين مع نفس مجلد الإخراج. إذا كان ملف PDF يشير إلى نفس الملف من كلا المكانين، فإن GetSafeOutputPath يحفظ النسخة الثانية باسم مرقم بدلاً من استبدال النسخة الأولى.

الخطوات التالية

للتعمق أكثر في المرفقات، مثل الإضافة أو الإزالة أو سردها دون استخراج، راجع توثيق Aspose.PDF for .NET. يدرج مرجع فئة FileSpecification خصائص الاسم الآخر والوصف التي يمكنك قراءتها من كل ملف مضمّن. إذا لم يتم استخراج ملف PDF كما هو متوقع، انشر عينة في منتدى دعم Aspose.PDF.

الأسئلة المتكررة

  1. كيف يختار FileSpecification.GetFileName اسمًا؟
    يقوم بحل الاسم من اسم Unicode للملف المضمّن، أو اسم الملف العادي، أو مفتاح المجموعة، أيًا كان متاحًا. إذا لم يتوفر أي منها، فإنه يُعيد الاسم الاحتياطي الذي تمرره. تم إضافة هذه الطريقة في Aspose.PDF for .NET 26.9.

  2. هل يعمل هذا مع ملفات PDF التي ليست محافظًا؟ نعم، بالنسبة للملفات المرفقة على مستوى المستند. الملفات المرفقة بصفحة محددة عبر ملاحظة مرفق ملف (عادةً ما تُظهر كرمز مشبك ورق) تُخزن على الملاحظة بدلاً من ذلك، لذا اقرأها من FileAttachmentAnnotation.File، كما هو موضح في استخراج الملفات المرفقة بالصفحات.

  3. لماذا يتم تغليف نتيجة GetFileName داخل Path.GetFileName؟ الاسم المخزن في ملف PDF يتم تحديده من قبل من أنشأ الملف ويمكن أن يتضمن أجزاء من المجلد. Path.GetFileName يحتفظ فقط باسم الملف، لذا يتم كتابة كل مرفق داخل مجلد الإخراج الخاص بك.

  4. ماذا يحدث إذا كان لدى مرفقين نفس الاسم؟ باستخدام FileMode.Create، يتم استبدال الملف الثاني بالملف الأول. تحقق مما إذا كان المسار موجودًا بالفعل وأضف لاحقة رقمية، كما هو موضح في معالجة الأسماء المكررة وغير الآمنة.

  5. هل يمكنني معالجة مرفق دون حفظه على القرص؟ نعم. الخاصية Contents هي Stream، لذلك يمكنك نسخها إلى MemoryStream، أو تحميلها، أو تمريرها إلى مكتبة أخرى بدلاً من كتابتها إلى FileStream.