C# iTextSharp提取PDF时PdfArray转PRIndirectReference报错如何解决
问题根因
PDF规范中页面的/Contents属性支持两种存储格式:
- 单内容流:存储为单个
PRIndirectReference指向流对象,即你原有代码兼容的场景 - 多内容流:存储为
PdfArray数组,每个元素均为指向内容流的PRIndirectReference,你遇到报错的PDF就属于该场景
修改后完整代码
List<string> stringsList = new List<string>(); // 你原有excludeList、excludeHeaders的定义保持不变 for (int page = 1; page <= reader.NumberOfPages; page++) { var cpage = reader.GetPageN(page); var content = cpage.Get(PdfName.CONTENTS); // 新增类型判断,兼容两种CONTENTS格式 if (content is PdfArray contentArray) { // 遍历数组内的所有流引用 foreach (var arrItem in contentArray) { ProcessContentStream(arrItem, reader, excludeList, excludeHeaders, stringsList); } } else if (content is PRIndirectReference ir) { // 单流场景走原有逻辑 ProcessContentStream(ir, reader, excludeList, excludeHeaders, stringsList); } } // 抽离的流处理公共方法,保留你原有全部过滤逻辑 void ProcessContentStream(PdfObject contentObj, PdfReader reader, List<string> excludeList, List<string> excludeHeaders, List<string> stringsList) { var ir = (PRIndirectReference)contentObj; var value = reader.GetPdfObject(ir.Number); if (value.IsStream()) { PRStream stream = (PRStream)value; var streamBytes = PdfReader.GetStreamBytes(stream); var tokenizer = new PRTokeniser(new RandomAccessFileOrArray(streamBytes)); try { while (tokenizer.NextToken()) { if (tokenizer.TokenType == PRTokeniser.TK_STRING) { string strs = tokenizer.StringValue; bool br = excludeList.Any(st => strs.Contains(st)); if (!br) { if (!string.IsNullOrWhiteSpace(strs) && !stringsList.Any(i => i == strs && excludeHeaders.Contains(strs))) { stringsList.Add(strs); } } } } } finally { tokenizer.Close(); } } }
修改说明
- 新增了
/Contents返回值的类型判断逻辑,同时兼容单流、多流两种PDF存储结构,解决类型转换报错 - 将原有的流解析逻辑抽为公共方法,避免代码冗余
- 你原有的排除关键词、过滤页眉的业务逻辑完全保留,不会影响原有过滤效果
内容的提问来源于stack exchange,提问作者StackUseR
相关产品推荐
相关产品推荐

