A PDF dapat membawa file lain di dalamnya. Itu dapat menjadi portofolio yang menggabungkan kontrak dan spreadsheet, atau laporan dengan data sumber terlampir. Saat Anda mengambil file‑file tersebut dalam kode, Anda ingin setiap file disimpan dengan nama yang diberikan penulisnya, bukan attachment1.bin. Tutorial ini menunjukkan cara mengekstrak file tersemat dari PDF dengan nama asli dalam C# menggunakan Aspose.PDF for .NET. Anda akan membuka PDF, melakukan iterasi melalui file tersematnya, menentukan nama setiap file dengan FileSpecification.GetFileName, dan menulis kontennya ke folder.

Di mana PDF menyimpan nama file yang disematkan

Setiap file tersemat dijelaskan oleh spesifikasi file, dan sebuah spesifikasi file dapat mencatat nama di lebih dari satu tempat. Ada nama file Unicode, nama file standar, dan kunci tempat file tersebut terdaftar dalam koleksi file tersemat dokumen. Produsen PDF tidak mengisi ini secara konsisten, dan beberapa menghilangkan nama tersebut sepenuhnya.

Aspose.PDF for .NET menyediakan properti FileSpecification.GetFileName untuk menangani hal ini. Properti ini memecahkan nama dari nama Unicode, nama file biasa, atau kunci koleksi, mana pun yang tersedia, sehingga Anda tetap mendapatkan nama yang dapat digunakan ketika nama Unicode tidak ada. Anda dapat memberikan nama cadangan untuk file yang tidak memiliki nama sama sekali. Parameter kedua opsional mengontrol apakah nama kosong diizinkan ketika tidak ada nama file yang tersedia. Anda mendapatkan satu panggilan alih‑alih menulis logika sendiri untuk membaca kamus PDF.

Catatan: Contoh-contoh dalam artikel ini hanya menggunakan argumen fallback.

Document.EmbeddedFiles menyimpan lampiran tingkat dokumen, yang mencakup file dalam portofolio PDF. File yang dilampirkan ke halaman tertentu melalui anotasi lampiran file (biasanya ditampilkan sebagai ikon penjepit kertas) disimpan pada anotasi tersebut; Ekstrak file yang dilampirkan ke halaman mencakup hal itu.

Menggunakan Aspose.PDF untuk mengekstrak file tersemat dari PDF

Install-Package Aspose.PDF

Atau dengan .NET CLI:

dotnet add package Aspose.PDF
  • PDF yang berisi file tersemat. Contohnya menggunakan portofolio bernama PDFPortfolio.pdf

Tanpa lisensi, Aspose.PDF berjalan dalam mode evaluasi. Untuk menguji tanpa batasan evaluasi, minta lisensi sementara gratis.

Ekstrak setiap file tersemat dengan nama aslinya

Metode berikut membuka PDF, menyimpan setiap file tersemat ke folder output dengan nama yang telah di‑resolve, dan mencetak jalur setiap file yang ditulisnya.

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

Panggil dengan path PDF dan folder tempat Anda menginginkan file berada:

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

Apa yang dilakukan setiap langkah

Buka dokumen. new Document(inputPdf) memuat PDF. Blok using melepaskan pegangan file ketika pemrosesan selesai, bahkan jika terjadi pengecualian.

Iterasi melalui lampiran. document.EmbeddedFiles mengembalikan satu FileSpecification untuk setiap file tersemat pada tingkat dokumen.

Tentukan nama. fileSpec.GetFileName("attachment.bin") mengembalikan nama yang disimpan, atau attachment.bin jika PDF tidak menyediakan nama. Pilih fallback yang masuk akal untuk aplikasi Anda.

Hapus segmen folder. Nama yang disimpan dapat mencakup jalur seperti reports/2026/q3.xlsx, atau nilai yang dibuat seperti ..\..\startup.bat. Menyampaikan hasil melalui Path.GetFileName menguranginya menjadi q3.xlsx atau startup.bat, sehingga file tidak dapat ditulis di luar outputDir. Pertahankan langkah ini bahkan jika Anda mempercayai PDF yang Anda proses hari ini.

Tulis kontennya. fileSpec.Contents adalah aliran data file yang disematkan. CopyTo menuliskannya ke file baru tanpa konversi apa pun.

Hasil yang diharapkan

Folder output berisi satu file untuk setiap lampiran tingkat dokumen, dinamai sebagaimana disimpan dalam PDF. Untuk sebuah portfolio yang berisi spreadsheet dan dokumen Word, output konsol terlihat serupa dengan ini:

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

Nama file tergantung pada PDF Anda. File yang diekstrak berisi data yang sama seperti yang disematkan, sehingga masing‑masing dapat dibuka di aplikasi apa pun yang menangani formatnya.

Menangani nama duplikat dan tidak aman

Contoh dasar memiliki tiga titik lemah yang akan Anda temui pada PDF dunia nyata:

  • Dua lampiran dapat memiliki nama yang sama, dan FileMode.Create secara diam-diam menimpa yang pertama. Ini juga terjadi ketika beberapa lampiran tidak memiliki nama dan semuanya kembali ke attachment.bin.
  • Nama yang valid pada satu sistem operasi dapat berisi karakter yang tidak valid pada sistem lain, seperti : pada Windows.
  • Nama yang disimpan yang berakhir dengan pemisah jalur membuat Path.GetFileName menghasilkan string kosong.

Pembantu ini menangani ketiganya. Ia mengganti karakter yang tidak valid, menggunakan nilai cadangan ketika nama kosong, dan menambahkan penghitung ketika file sudah ada:

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

Dalam loop ekstraksi, ganti dua baris yang membangun fileName dan outputPath dengan:

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

Karena helper memeriksa file yang sudah ada, menjalankan ekstraksi dua kali ke folder yang sama menghasilkan salinan bernomor alih‑alih menimpa. Bersihkan folder terlebih dahulu jika Anda menginginkan hasil baru pada setiap run.

Ekstrak file yang dilampirkan pada halaman

Jika EmbeddedFiles kosong tetapi Anda dapat melihat ikon penjepit kertas di penampil PDF, file tersebut kemungkinan terlampir melalui anotasi lampiran file pada halaman. Anotasi tersebut menyimpan FileSpecification miliknya sendiri di properti File, sehingga resolusi nama yang sama dan pembantu yang sama berlaku. Metode ini memeriksa setiap halaman dan menyimpan setiap file terlampir ke folder output:

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

Untuk mengumpulkan setiap lampiran dalam PDF, jalankan kedua metode dengan folder output yang sama. Jika sebuah PDF merujuk file yang sama dari kedua tempat, GetSafeOutputPath menyimpan salinan kedua dengan nama berangka alih‑alih menimpa yang pertama.

Langkah selanjutnya

Untuk melanjutkan dengan lampiran, seperti menambahkan, menghapus, atau menampilkan daftar tanpa mengekstrak, lihat dokumentasi Aspose.PDF for .NET. Referensi kelas FileSpecification mencantumkan properti nama lain dan deskripsi yang dapat Anda baca dari setiap file yang disematkan. Jika PDF tidak diekstrak seperti yang diharapkan, kirim contoh di forum dukungan Aspose.PDF.

FAQ

  1. Bagaimana FileSpecification.GetFileName memilih nama? Ia menentukan nama dari nama Unicode file yang tersemat, nama file biasa, atau kunci koleksi, mana pun yang tersedia. Jika tidak ada yang tersedia, ia mengembalikan nama cadangan yang Anda berikan. Metode ini ditambahkan dalam Aspose.PDF for .NET 26.9.

  2. Apakah ini berfungsi untuk PDF yang bukan portofolio? Ya, untuk file yang dilampirkan pada tingkat dokumen. File yang dilampirkan ke halaman tertentu melalui anotasi lampiran file (biasanya ditampilkan sebagai ikon penjepit kertas) disimpan pada anotasi tersebut, jadi baca mereka dari FileAttachmentAnnotation.File, seperti yang ditunjukkan di Ekstrak file yang dilampirkan ke halaman.

  3. Mengapa membungkus hasil GetFileName dengan Path.GetFileName? Nama yang disimpan dalam PDF ditetapkan oleh siapa pun yang membuat file tersebut dan dapat mencakup segmen folder. Path.GetFileName hanya menyimpan nama file, sehingga setiap lampiran ditulis di dalam folder output Anda.

  4. Apa yang terjadi jika dua lampiran memiliki nama yang sama? Dengan FileMode.Create, file kedua menimpa file pertama. Periksa apakah jalur sudah ada dan tambahkan akhiran numerik, seperti yang ditunjukkan di Handle duplicate and unsafe names.

  5. Bisakah saya memproses lampiran tanpa menyimpannya ke disk? Ya. Properti Contents adalah Stream, jadi Anda dapat menyalinnya ke MemoryStream, mengunggahnya, atau meneruskannya ke perpustakaan lain alih‑alih menulisnya ke FileStream.