Un PDF può contenere altri file al suo interno. Può essere un portfolio che raggruppa contratti e fogli di calcolo, oppure un report con i dati di origine allegati. Quando estrai quei file nel codice, vuoi che ciascuno sia salvato con il nome assegnato dall’autore, non come attachment1.bin. Questo tutorial mostra come estrarre i file incorporati da un PDF con i nomi originali in C# usando Aspose.PDF for .NET. Aprirai un PDF, percorrerai i suoi file incorporati, risolverai il nome di ciascun file con FileSpecification.GetFileName e scriverai il contenuto in una cartella.

Dove un PDF memorizza il nome di un file incorporato

Ogni file incorporato è descritto da una specifica di file e una specifica di file può registrare il nome in più di un punto. Esiste un nome file Unicode, un nome file standard e la chiave con cui il file è elencato nella raccolta di file incorporati del documento. I produttori di PDF non compilano questi campi in modo coerente e alcuni omettono del tutto il nome.

Aspose.PDF for .NET fornisce la proprietà FileSpecification.GetFileName per gestire questo. Risolve il nome dal nome Unicode, dal nome file normale o dalla chiave della raccolta, a seconda di quale sia disponibile, così ottieni comunque un nome utilizzabile quando il nome Unicode è mancante. È possibile fornire un nome di fallback per i file che non hanno alcun nome. Un secondo parametro opzionale controlla se è consentito un nome vuoto quando non è disponibile alcun nome file. Ottieni una sola chiamata invece della tua logica personalizzata per leggere i dizionari PDF.

Nota: gli esempi in questo articolo utilizzano solo l’argomento di fallback.

Il Document.EmbeddedFiles contiene gli allegati a livello di documento, che includono i file in un portfolio PDF. I file allegati a una pagina specifica tramite un’annotazione di allegato file (di solito mostrata come un’icona a graffetta) sono memorizzati sull’annotazione; Estrai i file allegati alle pagine copre questi.

Utilizzare Aspose.PDF per estrarre file incorporati da un PDF

Install-Package Aspose.PDF

Oppure con la CLI .NET:

dotnet add package Aspose.PDF
  • Un PDF che contiene file incorporati. L’esempio utilizza un portfolio denominato PDFPortfolio.pdf.

Senza una licenza, Aspose.PDF funziona in modalità di valutazione. Per testare senza restrizioni di valutazione, richiedi una licenza temporanea gratuita.

Estrai ogni file incorporato con il suo nome originale

Il metodo seguente apre il PDF, salva ogni file incorporato in una cartella di output con il suo nome risolto e stampa il percorso di ogni file che scrive.

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

Chiamalo con il percorso del PDF e la cartella in cui desideri i file:

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

Cosa fa ogni passaggio

Apri il documento. new Document(inputPdf) carica il PDF. Il blocco using rilascia il handle del file quando l’elaborazione termina, anche se viene sollevata un’eccezione.

Scorri gli allegati. document.EmbeddedFiles restituisce un FileSpecification per ogni file incorporato a livello di documento.

Risolvi il nome. fileSpec.GetFileName("attachment.bin") restituisce il nome memorizzato, oppure attachment.bin se il PDF non lo fornisce. Scegli un valore di fallback che abbia senso per la tua applicazione.

Rimuovere i segmenti di cartella. Un nome memorizzato può includere un percorso come reports/2026/q3.xlsx, o un valore manipolato come ..\..\startup.bat. Passare il risultato attraverso Path.GetFileName lo riduce a q3.xlsx o startup.bat, quindi il file non può essere scritto al di fuori di outputDir. Mantieni questo passaggio anche se ti fidi dei PDF che elabori oggi.

Scrivi il contenuto. fileSpec.Contents è un flusso dei dati del file incorporato. CopyTo lo scrive nel nuovo file senza alcuna conversione.

Risultato atteso

La cartella di output contiene un file per ogni allegato a livello di documento, denominato come è stato memorizzato nel PDF. Per un portfolio che contiene un foglio di calcolo e un documento Word, l’output della console appare simile a questo:

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

I nomi dei file dipendono dal tuo PDF. I file estratti contengono gli stessi dati che sono stati incorporati, quindi ciascuno si apre nell’applicazione che gestisce il suo formato.

Gestire nomi duplicati e non sicuri

L’esempio base presenta tre punti deboli che incontrerai con i PDF del mondo reale:

  • Due allegati possono condividere lo stesso nome e FileMode.Create sovrascrive silenziosamente il primo. Questo accade anche quando diversi allegati non hanno nome e tutti ricadono su attachment.bin.
  • Un nome valido su un sistema operativo può contenere caratteri non validi su un altro, come : su Windows.
  • Un nome memorizzato che termina con un separatore di percorso lascia Path.GetFileName con una stringa vuota.

Questo helper gestisce tutti e tre. Sostituisce i caratteri non validi, ricade su un valore predefinito quando il nome è vuoto e aggiunge un contatore quando il file esiste già:

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

Nel ciclo di estrazione, sostituisci le due righe che costruiscono fileName e outputPath con:

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

Poiché l’helper verifica la presenza di file esistenti, eseguire l’estrazione due volte nella stessa cartella produce copie numerate anziché sovrascrivere. Svuota la cartella prima se desideri un risultato nuovo a ogni esecuzione.

Estrai i file allegati alle pagine

Se EmbeddedFiles è vuoto ma vedi un’icona a graffetta in un visualizzatore PDF, il file è probabilmente allegato tramite un’annotazione di allegato file su una pagina. L’annotazione contiene la propria FileSpecification nella proprietà File, quindi si applicano la stessa risoluzione dei nomi e lo stesso helper. Questo metodo controlla ogni pagina e salva ogni file allegato nella cartella di 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}");
                }
            }
        }
    }
}

Per raccogliere tutti gli allegati in un PDF, esegui entrambi i metodi nella stessa cartella di output. Se un PDF fa riferimento allo stesso file da entrambi i luoghi, GetSafeOutputPath salva la seconda copia con un nome numerato anziché sovrascrivere la prima.

Passaggi successivi

Per approfondire gli allegati, come aggiungere, rimuovere o elencarli senza estrarli, consulta la documentazione di Aspose.PDF for .NET. Il riferimento della classe FileSpecification elenca le proprietà other name e description che puoi leggere da ogni file incorporato. Se un PDF non si estrae come previsto, pubblica un esempio nel forum di supporto di Aspose.PDF.

Domande frequenti

  1. Come sceglie un nome FileSpecification.GetFileName? Risolve il nome dal nome Unicode del file incorporato, dal nome file regolare o dalla chiave della collezione, a seconda di quale sia disponibile. Se nessuno è disponibile, restituisce il nome di fallback che si passa. Il metodo è stato aggiunto in Aspose.PDF for .NET 26.9.

  2. Funziona anche per i PDF che non sono portfolio? Sì, per i file allegati a livello di documento. I file allegati a una pagina specifica tramite un’annotazione di allegato file (solitamente mostrata come un’icona a graffetta) sono memorizzati sull’annotazione, quindi leggili da FileAttachmentAnnotation.File, come mostrato in Estrai i file allegati alle pagine.

  3. Perché avvolgere il risultato di GetFileName in Path.GetFileName? Il nome memorizzato in un PDF è impostato da chi ha creato il file e può includere segmenti di cartella. Path.GetFileName conserva solo il nome del file, quindi ogni allegato viene scritto nella tua cartella di output.

  4. Cosa succede se due allegati hanno lo stesso nome?
    Con FileMode.Create, il secondo file sovrascrive il primo. Verifica se il percorso esiste già e aggiungi un suffisso numerico, come mostrato in Gestisci nomi duplicati e non sicuri.

  5. Posso elaborare un allegato senza salvarlo su disco? Sì. La proprietà Contents è un Stream, quindi è possibile copiarlo in un MemoryStream, caricarlo o passarne a un’altra libreria invece di scriverlo in un FileStream.