如何用C#列出PDF内嵌文件并获取其只读文件流?
刚好我之前做过类似的需求,用C#处理PDF内嵌文件最靠谱的方式是借助成熟的PDF处理库,比如iTextSharp(或者它的升级版本iText 7,这里先以经典的iTextSharp为例,API更直观易上手)。
首先你需要通过NuGet安装iTextSharp包:在NuGet包管理器里搜索iTextSharp并安装,或者用Package Manager Console执行:
Install-Package iTextSharp
1. 列出PDF中的内嵌文件
这个功能需要遍历PDF文档的目录字典,找到内嵌文件的列表并提取文件名:
using System.Collections.Generic; using System.IO; using iTextSharp.text.pdf; public static List<string> ListPdfEmbeddedFiles(string pdfFilePath) { var embeddedFileNames = new List<string>(); // 打开PDF阅读器,自动释放资源 using (var pdfReader = new PdfReader(pdfFilePath)) { // 获取PDF的根目录字典 PdfDictionary catalog = pdfReader.Catalog; // 获取Names字典,里面存储了各类命名对象(包括内嵌文件) PdfDictionary namesDict = catalog.GetAsDict(PdfName.NAMES); if (namesDict != null) { // 获取内嵌文件的字典 PdfDictionary embeddedFilesDict = namesDict.GetAsDict(PdfName.EMBEDDEDFILES); if (embeddedFilesDict != null) { // 内嵌文件列表是一个数组,每两个元素为一组:文件名 + 文件引用 PdfArray filesArray = embeddedFilesDict.GetAsArray(PdfName.NAMES); if (filesArray != null) { for (int i = 0; i < filesArray.Size; i += 2) { // 提取文件名并加入列表 string fileName = filesArray.GetAsString(i).ToString(); embeddedFileNames.Add(fileName); } } } } } return embeddedFileNames; }
调用示例:
var files = ListPdfEmbeddedFiles(@"C:\your-file.pdf"); foreach (var file in files) { Console.WriteLine($"内嵌文件:{file}"); }
2. 获取指定内嵌文件的只读文件流
找到目标文件后,我们可以提取它的二进制流,转成只读的MemoryStream返回:
using System.IO; using System; using iTextSharp.text.pdf; public static Stream GetEmbeddedFileReadOnlyStream(string pdfFilePath, string targetFileName) { using (var pdfReader = new PdfReader(pdfFilePath)) { PdfDictionary catalog = pdfReader.Catalog; PdfDictionary namesDict = catalog.GetAsDict(PdfName.NAMES); if (namesDict != null) { PdfDictionary embeddedFilesDict = namesDict.GetAsDict(PdfName.EMBEDDEDFILES); if (embeddedFilesDict != null) { PdfArray filesArray = embeddedFilesDict.GetAsArray(PdfName.NAMES); if (filesArray != null) { for (int i = 0; i < filesArray.Size; i += 2) { string currentFileName = filesArray.GetAsString(i).ToString(); // 匹配目标文件名(忽略大小写) if (currentFileName.Equals(targetFileName, StringComparison.OrdinalIgnoreCase)) { // 获取文件的间接引用 PdfIndirectReference fileRef = filesArray.GetAsIndirectObject(i + 1); PdfDictionary fileDict = pdfReader.GetPdfObject(fileRef) as PdfDictionary; if (fileDict != null) { // 获取内嵌文件的流字典 PdfDictionary embeddedFileDict = fileDict.GetAsDict(PdfName.EF); if (embeddedFileDict != null) { // 提取文件流 PdfStream fileStream = embeddedFileDict.GetAsStream(PdfName.F); if (fileStream != null) { // 将流转为字节数组,再包装成只读MemoryStream byte[] fileBytes = PdfReader.GetStreamBytes(fileStream); return new MemoryStream(fileBytes).AsReadOnly(); } } } break; } } } } } } // 如果未找到目标文件,返回null return null; }
调用示例:
using (var stream = GetEmbeddedFileReadOnlyStream(@"C:\your-file.pdf", "abc.data")) { if (stream != null) { // 这里可以读取流内容,比如转成字符串或者写入本地文件 using (var reader = new StreamReader(stream)) { string content = reader.ReadToEnd(); Console.WriteLine(content); } } }
注意事项
- 异常处理:实际使用时建议添加
try-catch块,处理文件不存在、PDF损坏、权限不足等异常情况。 - 许可证:iTextSharp用于商业项目需要购买商业许可证,非商业项目可免费使用;如果是商业场景,也可以考虑使用其他开源库如PdfSharp(不过PdfSharp处理内嵌文件的API相对繁琐一些)。
- 编码问题:如果内嵌文件是文本类型,读取时要注意匹配对应的编码格式。
内容的提问来源于stack exchange,提问作者Wollmich
相关产品推荐
相关产品推荐

