Um PDF pode conter outros arquivos dentro dele. Pode ser um portfólio que agrupa contratos e planilhas, ou um relatório com seus dados de origem anexados. Quando você extrai esses arquivos no código, deseja que cada um seja salvo com o nome que o autor deu, não attachment1.bin. Este tutorial mostra como extrair arquivos incorporados de um PDF com os nomes originais em C# usando Aspose.PDF for .NET. Você abrirá um PDF, percorrerá seus arquivos incorporados, resolverá o nome de cada arquivo com FileSpecification.GetFileName e gravará o conteúdo em uma pasta.
Onde um PDF armazena o nome de um arquivo incorporado
Cada arquivo incorporado é descrito por uma especificação de arquivo, e uma especificação de arquivo pode registrar o nome em mais de um local. Existe um nome de arquivo Unicode, um nome de arquivo padrão e a chave sob a qual o arquivo está listado na coleção de arquivos incorporados do documento. Os produtores de PDF não preenchem esses campos de forma consistente, e alguns deixam o nome totalmente ausente.
Aspose.PDF for .NET fornece a propriedade FileSpecification.GetFileName para lidar com isso. Ela resolve o nome a partir do nome Unicode, do nome de arquivo regular ou da chave da coleção, conforme estiver disponível, de modo que você ainda obtenha um nome utilizável quando o nome Unicode estiver ausente. Você pode passar um nome de fallback para arquivos que não têm nenhum nome. Um segundo parâmetro opcional controla se um nome vazio é permitido quando nenhum nome de arquivo está disponível. Você obtém uma única chamada em vez de sua própria lógica para ler dicionários PDF.
Observação: os exemplos neste artigo usam apenas o argumento de fallback.
O Document.EmbeddedFiles contém anexos ao nível do documento, que inclui os arquivos em um portfólio PDF. Arquivos anexados a uma página específica por meio de uma anotação de anexo de arquivo (geralmente exibida como um ícone de clipe) são armazenados na anotação; Extrair arquivos anexados às páginas cobre esses.
Usando Aspose.PDF para extrair arquivos incorporados de um PDF
- Um projeto .NET.
- Aspose.PDF for .NET 26.9 ou posterior, que é a versão que introduziu
FileSpecification.GetFileName. Instale-o a partir do NuGet:
Install-Package Aspose.PDF
Ou com a CLI do .NET:
dotnet add package Aspose.PDF
- Um PDF que contém arquivos incorporados. O exemplo usa um portfólio chamado
PDFPortfolio.pdf.
Sem uma licença, Aspose.PDF funciona no modo de avaliação. Para testar sem restrições de avaliação, solicite uma licença temporária gratuita.
Extrair cada arquivo incorporado com seu nome original
O método a seguir abre o PDF, salva cada arquivo incorporado em uma pasta de saída com seu nome resolvido e imprime o caminho de cada arquivo que ele grava.
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}");
}
}
}
}
Chame‑o com o caminho do PDF e a pasta onde você deseja os arquivos:
EmbeddedFileExtractor.ExtractEmbeddedFiles("PDFPortfolio.pdf", "ExtractedFiles");
O que cada passo faz
Abra o documento. new Document(inputPdf) loads the PDF. O bloco using libera o identificador do arquivo quando o processamento termina, mesmo que uma exceção seja lançada.
Percorra os anexos. document.EmbeddedFiles retorna um FileSpecification para cada arquivo incorporado ao nível do documento.
Resolver o nome. fileSpec.GetFileName("attachment.bin") retorna o nome armazenado, ou attachment.bin se o PDF não fornecer nenhum. Escolha um fallback que faça sentido para sua aplicação.
Remover segmentos de pasta. Um nome armazenado pode incluir um caminho como reports/2026/q3.xlsx, ou um valor forjado como ..\..\startup.bat. Passar o resultado por Path.GetFileName reduz‑o a q3.xlsx ou startup.bat, de modo que o arquivo não possa ser gravado fora de outputDir. Mantenha esta etapa mesmo que você confie nos PDFs que processa hoje.
Escreva o conteúdo. fileSpec.Contents é um fluxo dos dados do arquivo incorporado. CopyTo grava‑o no novo arquivo sem qualquer conversão.
Resultado esperado
A pasta de saída contém um arquivo para cada anexo ao nível do documento, nomeado como foi armazenado no PDF. Para um portfólio que contém uma planilha e um documento Word, a saída do console se parece com isto:
Saved: ExtractedFiles\budget-2026.xlsx
Saved: ExtractedFiles\service-agreement.docx
Os nomes dos arquivos dependem do seu PDF. Os arquivos extraídos contêm os mesmos dados que foram incorporados, portanto cada um abre no aplicativo que lida com seu formato.
Manipular nomes duplicados e inseguros
O exemplo básico tem três pontos fracos que você encontrará em PDFs do mundo real:
- Dois anexos podem compartilhar um nome, e
FileMode.Createsobrescreve silenciosamente o primeiro. Isso também ocorre quando vários anexos não têm nome e todos retornam paraattachment.bin. - Um nome que é válido em um sistema operacional pode conter caracteres que são inválidos em outro, como
:no Windows. - Um nome armazenado que termina com um separador de caminho deixa
Path.GetFileNamecom uma string vazia.
Este auxiliar lida com os três casos. Ele substitui caracteres inválidos, recorre a um valor padrão quando o nome está vazio e adiciona um contador quando o arquivo já existe:
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;
}
No loop de extração, substitua as duas linhas que constroem fileName e outputPath por:
string outputPath = GetSafeOutputPath(outputDir, fileSpec.GetFileName("attachment.bin"), "attachment.bin");
Como o assistente verifica arquivos existentes, executar a extração duas vezes na mesma pasta produz cópias numeradas em vez de sobrescrever. Limpe a pasta primeiro se quiser um resultado novo a cada execução.
Extrair arquivos anexados às páginas
Se EmbeddedFiles estiver vazio, mas você puder ver um ícone de clipe de papel em um visualizador de PDF, o arquivo provavelmente está anexado por meio de uma anotação de anexo de arquivo em uma página. A anotação contém sua própria FileSpecification na propriedade File, portanto a mesma resolução de nome e o mesmo auxiliar são aplicados. Este método verifica cada página e salva cada arquivo anexado na pasta de saída:
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}");
}
}
}
}
}
Para coletar todos os anexos em um PDF, execute ambos os métodos na mesma pasta de saída. Se um PDF referenciar o mesmo arquivo de ambos os locais, GetSafeOutputPath salva a segunda cópia com um nome numerado em vez de sobrescrever a primeira.
Próximos passos
Para avançar mais com anexos, como adicionar, remover ou listá‑los sem extrair, consulte a documentação do Aspose.PDF for .NET. A referência da classe FileSpecification lista as propriedades other name e description que você pode ler de cada arquivo incorporado. Se um PDF não for extraído como esperado, publique um exemplo no fórum de suporte do Aspose.PDF.
Perguntas Frequentes
Como o FileSpecification.GetFileName escolhe um nome? Ele resolve o nome a partir do nome Unicode do arquivo incorporado, do nome de arquivo regular ou da chave da coleção, conforme estiver disponível. Se nenhum estiver disponível, ele retorna o nome de fallback que você fornece. O método foi adicionado no Aspose.PDF for .NET 26.9.
Isso funciona para PDFs que não são portfolios? Sim, para arquivos anexados ao nível do documento. Arquivos anexados a uma página específica por meio de uma anotação de anexo de arquivo (geralmente exibida como um ícone de clipe) são armazenados na anotação, portanto, leia‑os de
FileAttachmentAnnotation.File, como mostrado em Extrair arquivos anexados às páginas.Por que envolver o resultado de GetFileName em Path.GetFileName? O nome armazenado em um PDF é definido por quem criou o arquivo e pode incluir segmentos de pasta.
Path.GetFileNamemantém apenas o nome do arquivo, de modo que cada anexo é gravado dentro da sua pasta de saída.O que acontece se dois anexos tiverem o mesmo nome? Com
FileMode.Create, o segundo arquivo sobrescreve o primeiro. Verifique se o caminho já existe e adicione um sufixo numérico, como mostrado em Manipular nomes duplicados e inseguros.Posso processar um anexo sem salvá‑lo no disco? Sim. A propriedade
Contentsé umStream, então você pode copiá‑lo para umMemoryStream, enviá‑lo ou passá‑lo para outra biblioteca em vez de gravá‑lo em umFileStream.
