Một PDF có thể chứa các tệp khác bên trong. Nó có thể là một danh mục gộp hợp đồng và bảng tính, hoặc một báo cáo kèm dữ liệu nguồn. Khi bạn trích xuất các tệp đó trong mã, bạn muốn mỗi tệp được lưu với tên mà tác giả đã đặt, không phải attachment1.bin. Hướng dẫn này cho thấy cách trích xuất các tệp nhúng từ PDF với tên gốc trong C# bằng cách sử dụng Aspose.PDF for .NET. Bạn sẽ mở một PDF, lặp qua các tệp nhúng, xác định tên mỗi tệp bằng FileSpecification.GetFileName, và ghi nội dung vào một thư mục.

Nơi mà PDF lưu trữ tên của tệp được nhúng

Mỗi tệp được nhúng được mô tả bằng một đặc tả tệp, và một đặc tả tệp có thể ghi lại tên ở nhiều vị trí khác nhau. Có tên tệp Unicode, tên tệp chuẩn, và khóa mà tệp được liệt kê trong bộ sưu tập tệp nhúng của tài liệu. Các nhà sản xuất PDF không luôn điền đầy đủ các thông tin này một cách nhất quán, và một số lại bỏ hoàn toàn tên.

Aspose.PDF for .NET cung cấp thuộc tính FileSpecification.GetFileName để xử lý việc này. Nó giải quyết tên từ tên Unicode, tên tệp thông thường, hoặc khóa của bộ sưu tập, tùy theo cái nào có sẵn, vì vậy bạn vẫn nhận được một tên có thể sử dụng khi tên Unicode bị thiếu. Bạn có thể truyền một tên dự phòng cho các tệp không có tên nào cả. Tham số thứ hai tùy chọn kiểm soát việc cho phép tên trống khi không có tên tệp. Bạn chỉ cần một lần gọi thay vì tự viết logic để đọc các từ điển PDF.

Lưu ý: Các ví dụ trong bài viết này chỉ sử dụng đối số fallback.

Document.EmbeddedFiles giữ các tệp đính kèm ở mức tài liệu, bao gồm các tệp trong một danh mục PDF. Các tệp được đính kèm vào một trang cụ thể thông qua chú thích đính kèm tệp (thường hiển thị dưới dạng biểu tượng kẹp giấy) được lưu trên chú thích thay vì; Trích xuất các tệp đính kèm vào các trang bao gồm những tệp đó.

Sử dụng Aspose.PDF để trích xuất các tệp nhúng từ PDF

Install-Package Aspose.PDF

Hoặc với .NET CLI:

dotnet add package Aspose.PDF
  • Một PDF chứa các tệp được nhúng. Ví dụ sử dụng một portfolio có tên PDFPortfolio.pdf.

Không có giấy phép, Aspose.PDF chạy ở chế độ đánh giá. Để thử nghiệm mà không bị hạn chế đánh giá, hãy yêu cầu một giấy phép tạm thời miễn phí.

Trích xuất mọi tệp nhúng kèm tên gốc của chúng

Phương thức sau mở tệp PDF, lưu mỗi tệp nhúng vào một thư mục đầu ra dưới tên đã được giải quyết, và in ra đường dẫn của mỗi tệp mà nó ghi.

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}");
            }
        }
    }
}

Gọi nó với đường dẫn PDF và thư mục bạn muốn các tệp nằm trong đó:

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

Mỗi bước làm gì

Mở tài liệu. new Document(inputPdf) tải PDF. Khối using giải phóng handle tệp khi quá trình xử lý kết thúc, ngay cả khi có ngoại lệ được ném.

Lặp qua các tệp đính kèm. document.EmbeddedFiles trả về một FileSpecification cho mỗi tệp nhúng cấp tài liệu.

Giải quyết tên. fileSpec.GetFileName("attachment.bin") trả về tên đã lưu, hoặc attachment.bin nếu PDF không cung cấp. Chọn một phương án dự phòng có ý nghĩa cho ứng dụng của bạn.

Loại bỏ các đoạn thư mục. Một tên đã lưu có thể bao gồm một đường dẫn như reports/2026/q3.xlsx, hoặc một giá trị được tạo ra như ..\..\startup.bat. Việc truyền kết quả qua Path.GetFileName sẽ giảm nó thành q3.xlsx hoặc startup.bat, vì vậy tệp không thể được ghi ra ngoài outputDir. Hãy giữ bước này ngay cả khi bạn tin tưởng các PDF bạn xử lý hiện nay.

Ghi nội dung. fileSpec.Contents là một luồng dữ liệu của tệp được nhúng. CopyTo ghi nó vào tệp mới mà không thực hiện bất kỳ chuyển đổi nào.

Kết quả mong đợi

Thư mục đầu ra chứa một tệp cho mỗi tệp đính kèm ở mức tài liệu, được đặt tên như khi nó được lưu trong PDF. Đối với một danh mục chứa một bảng tính và một tài liệu Word, đầu ra console trông tương tự như sau:

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

Tên tệp phụ thuộc vào PDF của bạn. Các tệp đã trích xuất chứa cùng dữ liệu đã được nhúng, vì vậy mỗi tệp sẽ mở bằng bất kỳ ứng dụng nào xử lý định dạng của nó.

Xử lý các tên trùng lặp và không an toàn

Ví dụ cơ bản có ba điểm yếu mà bạn sẽ gặp phải với các tệp PDF thực tế:

  • Hai tệp đính kèm có thể cùng tên, và FileMode.Create sẽ ghi đè âm thầm tệp đầu tiên. Điều này cũng xảy ra khi một số tệp đính kèm không có tên và tất cả đều sử dụng attachment.bin.
  • Một tên hợp lệ trên một hệ điều hành có thể chứa các ký tự không hợp lệ trên hệ điều hành khác, chẳng hạn như : trên Windows.
  • Một tên đã lưu kết thúc bằng dấu phân tách đường dẫn sẽ khiến Path.GetFileName trả về chuỗi rỗng.

Trợ giúp này xử lý cả ba trường hợp. Nó thay thế các ký tự không hợp lệ, sử dụng giá trị dự phòng khi tên rỗng, và thêm bộ đếm khi tệp đã tồn tại:

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;
}

Trong vòng lặp giải nén, thay thế hai dòng tạo fileName và outputPath bằng:

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

Vì trợ giúp kiểm tra các tệp đã tồn tại, việc chạy quá trình trích xuất hai lần vào cùng một thư mục sẽ tạo ra các bản sao có số thứ tự thay vì ghi đè. Hãy xóa sạch thư mục trước nếu bạn muốn có kết quả mới mỗi lần chạy.

Trích xuất các tệp đính kèm vào các trang

Nếu EmbeddedFiles trống nhưng bạn thấy biểu tượng kẹp giấy trong trình xem PDF, tệp có thể đã được đính kèm thông qua chú thích đính kèm tệp trên một trang. Chú thích này chứa FileSpecification riêng của nó trong thuộc tính File, vì vậy cùng một cơ chế giải quyết tên và cùng một trợ giúp sẽ được áp dụng. Phương pháp này kiểm tra mọi trang và lưu mỗi tệp đính kèm vào thư mục đầu ra:

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}");
                }
            }
        }
    }
}

Để thu thập mọi tệp đính kèm trong một PDF, hãy chạy cả hai phương pháp với cùng một thư mục đầu ra. Nếu một PDF tham chiếu cùng một tệp từ cả hai vị trí, GetSafeOutputPath sẽ lưu bản sao thứ hai với tên có số thay vì ghi đè lên bản đầu tiên.

Các bước tiếp theo

Để tìm hiểu sâu hơn về các tệp đính kèm, chẳng hạn như thêm, xóa hoặc liệt kê chúng mà không cần giải nén, hãy xem tài liệu Aspose.PDF for .NET. Tham chiếu lớp FileSpecification liệt kê các thuộc tính tên khác và mô tả mà bạn có thể đọc từ mỗi tệp nhúng. Nếu một tệp PDF không được giải nén như mong đợi, hãy đăng mẫu trong diễn đàn hỗ trợ Aspose.PDF.

FAQs

  1. FileSpecification.GetFileName chọn tên như thế nào?
    Nó xác định tên từ tên Unicode của tệp được nhúng, tên tệp thông thường, hoặc khóa của bộ sưu tập, tùy theo cái nào có sẵn. Nếu không có nào có sẵn, nó sẽ trả về tên dự phòng mà bạn truyền vào. Phương thức này đã được thêm vào Aspose.PDF for .NET 26.9.

  2. Điều này có áp dụng cho các PDF không phải là portfolio không? Có, đối với các tệp được đính kèm ở mức tài liệu. Các tệp được đính kèm vào một trang cụ thể thông qua chú thích đính kèm tệp (thường hiển thị dưới dạng biểu tượng kẹp giấy) được lưu trên chú thích thay vì, vì vậy hãy đọc chúng từ FileAttachmentAnnotation.File, như được mô tả trong Extract files attached to pages.

  3. Tại sao cần bọc kết quả của GetFileName bằng Path.GetFileName? Tên được lưu trong PDF được đặt bởi người tạo tệp và có thể bao gồm các đoạn thư mục. Path.GetFileName chỉ giữ lại tên tệp, vì vậy mọi tệp đính kèm đều được ghi vào thư mục đầu ra của bạn.

  4. Điều gì xảy ra nếu hai tệp đính kèm có cùng tên? Với FileMode.Create, tệp thứ hai sẽ ghi đè lên tệp đầu tiên. Kiểm tra xem đường dẫn đã tồn tại chưa và thêm hậu tố số, như được mô tả trong Xử lý các tên trùng lặp và không an toàn.

  5. Có thể xử lý tệp đính kèm mà không lưu vào đĩa không? Có. Thuộc tính Contents là một Stream, vì vậy bạn có thể sao chép nó vào một MemoryStream, tải lên, hoặc truyền nó cho thư viện khác thay vì ghi nó vào một FileStream.