A PDF می‌تواند فایل‌های دیگری را در خود حمل کند. می‌تواند یک پورتفولیوی باشد که قراردادها و صفحات گسترده را در خود بسته‌بندی می‌کند، یا گزارشی با داده‌های منبع پیوست‌شده. وقتی این فایل‌ها را در کد استخراج می‌کنید، می‌خواهید هر یک تحت نامی که نویسنده آن داده ذخیره شود، نه attachment1.bin. این آموزش نشان می‌دهد چگونه فایل‌های توکار را از یک PDF با نام‌های اصلی استخراج کنید در C# با استفاده از Aspose.PDF for .NET. شما یک PDF را باز می‌کنید، به‌صورت حلقه‌ای بر فایل‌های توکار آن می‌گردید، نام هر فایل را با FileSpecification.GetFileName تعیین می‌کنید و محتوا را در یک پوشه می‌نویسید.

جایی که PDF نام فایل جاسازی‌شده را ذخیره می‌کند

هر فایل جاسازی‌شده توسط یک مشخصات فایل توصیف می‌شود و یک مشخصات فایل می‌تواند نام را در بیش از یک مکان ثبت کند. یک نام فایل یونیکد، یک نام فایل استاندارد، و کلیدی که فایل تحت آن در مجموعه فایل‌های جاسازی‌شده سند فهرست می‌شود وجود دارد. تولیدکنندگان PDF این موارد را به‌طور یکنواخت پر نمی‌کنند و برخی به‌طور کامل نام را حذف می‌کنند.

Aspose.PDF for .NET ویژگی FileSpecification.GetFileName را برای رسیدگی به این فراهم می‌کند. این نام را از نام یونیکد، نام فایل معمولی یا کلید مجموعه استخراج می‌کند، بسته به اینکه کدام یک موجود باشد، به‌طوری که حتی وقتی نام یونیکد موجود نیست، همچنان یک نام قابل استفاده دریافت می‌کنید. می‌توانید برای فایل‌هایی که اصلاً نام ندارند، یک نام جایگزین ارائه دهید. یک پارامتر دوم اختیاری تعیین می‌کند که آیا اجازهٔ نام خالی زمانی که نام فایلی موجود نیست، داده شود یا نه. به‌جای نوشتن منطق خود برای خواندن فرهنگ‌نامه‌های PDF، تنها یک فراخوانی دریافت می‌کنید.

توجه: مثال‌های این مقاله فقط از آرگومان fallback استفاده می‌کنند.

Document.EmbeddedFiles سندهای پیوست سطح سند را نگه می‌دارد که شامل فایل‌های موجود در یک پورتفولیوی PDF است. فایل‌های پیوست شده به صفحه خاصی از طریق حاشیه‌نویس پیوست فایل (معمولاً به شکل نماد گیره کاغذی نمایش داده می‌شود) بر روی همان حاشیه‌نویس ذخیره می‌شوند؛ Extract files attached to pages این موارد را پوشش می‌دهد.

استفاده از Aspose.PDF برای استخراج فایل‌های جاسازی‌شده از یک PDF

Install-Package Aspose.PDF

یا با .NET CLI:

dotnet add package Asprose.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 بازگردند.
  • نامی که در یک سیستم‌عامل معتبر است می‌تواند شامل کاراکترهایی باشد که در سیستم‌عامل دیگری نامعتبرند، مانند : در ویندوز.
  • نام ذخیره‌شده‌ای که با جداکننده مسیر پایان می‌یابد، باعث می‌شود 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 یک نام را انتخاب می‌کند؟ این نام را از نام یونیکد فایل جاسازی‌شده، نام فایل معمولی یا کلید مجموعه استخراج می‌کند، بسته به اینکه کدام یک موجود باشد. اگر هیچ‌کدام موجود نباشد، نام پیش‌فرضی که شما می‌گذارید را برمی‌گرداند. این متد در Aspose.PDF for .NET 26.9 اضافه شد.

  2. آیا این برای PDFهایی که پورتفولیو نیستند کار می‌کند؟ بله، برای فایل‌های پیوست‌شده در سطح سند. فایل‌های پیوست‌شده به صفحه خاصی از طریق حاشیه‌نویس پیوست فایل (که معمولاً به شکل آیکون گیره کاغذ نمایش داده می‌شود) به جای آن در حاشیه‌نویس ذخیره می‌شوند، بنابراین آن‌ها را از FileAttachmentAnnotation.File بخوانید، همان‌طور که در Extract files attached to pages نشان داده شده است.

  3. چرا نتیجه GetFileName را در Path.GetFileName بپیچیم؟ نام ذخیره‌شده در یک PDF توسط کسی که فایل را ایجاد کرده تنظیم می‌شود و می‌تواند شامل بخش‌های پوشه باشد. Path.GetFileName فقط نام فایل را نگه می‌دارد، بنابراین هر پیوست داخل پوشه خروجی شما نوشته می‌شود.

  4. چه اتفاقی می‌افتد اگر دو پیوست نام یکسان داشته باشند؟ با FileMode.Create، فایل دوم فایل اول را بازنویسی می‌کند. بررسی کنید که آیا مسیر از قبل وجود دارد و یک پسوند عددی اضافه کنید، همان‌طور که در Handle duplicate and unsafe names نشان داده شده است.

  5. آیا می‌توانم یک پیوست را بدون ذخیره‌سازی در دیسک پردازش کنم؟ بله. ویژگی Contents یک Stream است، بنابراین می‌توانید آن را به یک MemoryStream کپی کنید، بارگذاری کنید، یا به کتابخانه دیگری پاس دهید به جای اینکه آن را در یک FileStream بنویسید.