PDF는 내부에 다른 파일을 포함할 수 있습니다. 계약서와 스프레드시트를 묶은 포트폴리오이거나, 원본 데이터가 첨부된 보고서가 될 수 있습니다. 코드를 사용해 해당 파일들을 추출할 때, attachment1.bin과 같은 이름이 아니라 작성자가 지정한 원래 이름으로 저장하고 싶습니다. 이 튜토리얼에서는 Aspose.PDF for .NET을 사용하여 C#에서 PDF에 포함된 파일을 원래 이름으로 추출하는 방법을 보여줍니다. PDF를 열고, 포함된 파일들을 순회하며, FileSpecification.GetFileName을 사용해 각 파일의 이름을 확인하고, 내용을 폴더에 기록합니다.

PDF가 포함된 파일 이름을 저장하는 위치

각 포함된 파일은 파일 사양에 의해 설명되며, 파일 사양은 이름을 한 곳 이상에 기록할 수 있습니다. Unicode 파일 이름, 표준 파일 이름, 그리고 문서의 포함된 파일 컬렉션에 파일이 나열되는 키가 있습니다. PDF 제작자는 이를 일관되게 채우지 않으며, 일부는 이름을 전혀 포함하지 않기도 합니다.

Aspose.PDF for .NET은 이 문제를 처리하기 위해 FileSpecification.GetFileName 속성을 제공합니다. 이 속성은 유니코드 이름, 일반 파일 이름 또는 컬렉션 키 중 사용 가능한 것을 기준으로 이름을 해결하므로 유니코드 이름이 없을 때도 사용할 수 있는 이름을 얻을 수 있습니다. 이름이 전혀 없는 파일에 대해 대체 이름을 전달할 수 있습니다. 선택적인 두 번째 매개변수는 파일 이름이 없을 때 빈 이름을 허용할지 여부를 제어합니다. PDF 사전을 읽기 위한 자체 로직 대신 한 번의 호출로 처리할 수 있습니다.

참고: 이 문서의 예제는 오직 fallback 인수만 사용합니다.

Document.EmbeddedFiles는 문서 수준 첨부 파일을 보유하며, 여기에는 PDF 포트폴리오의 파일이 포함됩니다. 파일 첨부 주석(보통 클립 아이콘으로 표시)을 통해 특정 페이지에 첨부된 파일은 주석에 저장됩니다; 페이지에 첨부된 파일 추출에서 해당 내용을 다룹니다.

Aspose.PDF를 사용하여 PDF에서 포함된 파일 추출하기

Install-Package Aspose.PDF

또는 .NET CLI를 사용하여:

dotnet add package Aspose.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")는 저장된 이름을 반환하며, PDF가 제공하지 않을 경우 attachment.bin을 반환합니다. 애플리케이션에 맞는 대체값을 선택하십시오.

폴더 세그먼트 제거. 저장된 이름은 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으로 대체될 때도 발생합니다.
  • 한 운영 체제에서는 유효한 이름이 다른 운영 체제에서는 유효하지 않은 문자를 포함할 수 있습니다. 예를 들어 Windows에서는 :가 해당됩니다.
  • 경로 구분자로 끝나는 저장된 이름은 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 뷰어에서 클립 아이콘이 보인다면, 파일은 페이지의 파일 첨부 주석을 통해 첨부된 것일 가능성이 높습니다. 해당 주석은 File 속성에 자체 FileSpecification을 보유하고 있으므로 동일한 이름 해석 및 동일한 도우미가 적용됩니다. 이 메서드는 모든 페이지를 검사하고 각 첨부 파일을 출력 폴더에 저장합니다:

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 documentation을 참조하십시오. FileSpecification class reference에서는 각 포함된 파일에서 읽을 수 있는 다른 이름 및 설명 속성을 나열합니다. PDF가 예상대로 추출되지 않으면, Aspose.PDF support forum에 샘플을 게시하십시오.

자주 묻는 질문

  1. FileSpecification.GetFileName이 이름을 선택하는 방식은 무엇입니까? 임베디드 파일의 유니코드 이름, 일반 파일 이름 또는 컬렉션 키 중 사용 가능한 것을 기준으로 이름을 결정합니다. 사용 가능한 것이 없으면 전달한 대체 이름을 반환합니다. 이 메서드는 Aspose.PDF for .NET 26.9에 추가되었습니다.

  2. 포트폴리오가 아닌 PDF에서도 작동합니까? 예, 문서 수준에 첨부된 파일의 경우 작동합니다. 파일 첨부 주석(보통 클립 아이콘으로 표시)을 통해 특정 페이지에 첨부된 파일은 주석에 저장되므로, FileAttachmentAnnotation.File에서 읽어야 합니다. 자세한 내용은 페이지에 첨부된 파일 추출에서 확인하십시오.

  3. 왜 GetFileName 결과를 Path.GetFileName으로 감싸나요?
    PDF에 저장된 이름은 파일을 만든 사람이 지정하며 폴더 구분자를 포함할 수 있습니다. Path.GetFileName은 파일 이름만 남기므로 모든 첨부 파일이 출력 폴더에 기록됩니다.

  4. 두 개의 첨부 파일이 동일한 이름을 가질 경우 어떻게 되나요? FileMode.Create를 사용하면 두 번째 파일이 첫 번째 파일을 덮어씁니다. 경로가 이미 존재하는지 확인하고, 중복 및 안전하지 않은 이름 처리와 같이 숫자 접미사를 추가하십시오.

  5. 디스크에 저장하지 않고 첨부 파일을 처리할 수 있나요? 예. Contents 속성은 Stream이므로 MemoryStream에 복사하거나, 업로드하거나, FileStream에 쓰는 대신 다른 라이브러리에 전달할 수 있습니다.