PDFBox调用setStartPage/setEndPage读取指定PDF页面内容失效
问题产生原因
- 低版本PDFBox存在页面树解析bug:2.0.20之前的版本在处理带嵌套层级页面树的PDF时,页码索引计算会出现重复遍历的问题,导致设置的页码范围不生效。你使用的官方样例PDF是最简单的单层级页面树结构,不会触发这个bug,而你下载的特定PDF如果用了多层嵌套页面树,就会返回全文档内容。
- 加载方式不兼容线性化PDF:如果你下载的PDF是做过Web优化的线性化格式,使用
FileInputStream顺序流加载时,PDFBox无法正确解析页面索引映射,会默认读取全文档内容。结构简单的样例PDF不会触发这个问题,结构复杂的线性化PDF很容易出现页码配置失效。 - 物理页码与逻辑页码混淆:部分PDF会给目录、前言设置罗马数字等独立的页码标签,阅读器里显示的页码和PDF实际的物理页序号存在偏移,你传入的页码值对应的不是你预期的页面。
- PDF文件本身损坏:如果下载的文件存在字节缺失、页面对象引用异常,PDFBox容错解析时会生成错误的页码映射,导致页码范围配置失效。
修复方案
- 第一步先升级PDFBox依赖到2.0.x系列的最新稳定版本,2.0.21及之后的版本已经修复了嵌套页面树的页码计算bug,80%以上的同类问题升级后即可解决。
- 替换PDF加载逻辑,不要手动创建
FileInputStream传入PDDocument.load()方法,直接传入File对象,让PDFBox用随机访问模式读取文件,避免线性化PDF的解析异常,修正后的核心代码如下:
File file = new File(home + "/Downloads/" + fileDownloaded); // 直接加载File对象,无需手动创建输入流 PDDocument pdfDoc = PDDocument.load(file); PDFTextStripper reader = new PDFTextStripper(); reader.setStartPage(1); reader.setEndPage(1); String pageText = reader.getText(pdfDoc); // 处理完成后务必关闭文档释放资源 pdfDoc.close();
- 如果前两步操作后仍然异常,先调用
pdfDoc.getNumberOfPages()打印文档识别到的总页数,和你本地打开PDF看到的实际页数做对比:如果数值不一致,说明文件本身损坏,重新下载完整文件即可;如果数值一致但页码对应内容不对,手动调整传入setStartPage、setEndPage的数值,匹配物理页的实际序号即可,注意这两个方法的参数是从1开始计数的物理页序号,不是阅读器显示的逻辑页码。
内容的提问来源于stack exchange,提问作者Roger09
相关产品推荐
相关产品推荐

