PDFBox报COSStream已关闭错误 合并PDDocument页面异常如何解决?
问题根因
这个是PDFBox的典型错误:PDPage实例默认和创建它的PDDocument绑定,你直接将子文档的PDPage添加到主文档后,子文档一旦关闭,PDPage关联的COSStream资源就会被释放,主文档执行save操作读取页面资源时就会触发该异常。
你代码里的具体问题
- 跨文档添加页面用法错误:
setPreLastPage、setLastPage、addExtraPage三个方法里直接调用doc.addPage(p1),只是把PDPage的引用加到主文档,页面资源仍然绑定在方法内创建的activeDocument上 - 子文档资源管理错误:Java是值传递,你在方法内给参数
activeDocument重新赋值,完全不会修改方法外的activeDocument变量,方法内创建的所有子文档实例都没有被正确关闭,且主循环finally里关闭的只是最开始初始化的空PDDocument,完全没有作用 - 冗余代码:子文档内的
activeDocument.save(out)完全没用,你没有用到输出流的内容,属于多余操作
修复方案
- 替换跨文档加页面的逻辑,把所有
doc.addPage(p1)替换为:
// 导入页面会把所有资源复制到主文档,和原文档解绑 PDPage importedPage = doc.importPage(p1); doc.addPage(importedPage);
- 每个生成子页面的方法内,加完页面后立刻关闭当前创建的
activeDocument,示例修改:
public void setPreLastPage( PDDocument doc, ...){ PDDocument activeDocument = new PDDocument().load(getClass().getClassLoader().getResourceAsStream(pdf)); try { // 原有业务逻辑不变 PDDocumentCatalog docCatalog = activeDocument.getDocumentCatalog(); PDPage p1 = docCatalog.getPages().get(0); PDAcroForm acroForm = docCatalog.getAcroForm(); // 业务逻辑省略 acroForm.flatten(); PDPageContentStream cs = new PDPageContentStream(activeDocument, p1,PDPageContentStream.AppendMode.APPEND, true); cs.close(); // 删掉多余的activeDocument.save(out) // 导入页面到主文档 doc.addPage(doc.importPage(p1)); } finally { // 方法内创建的子文档自己关 if (activeDocument != null) { activeDocument.close(); } } }
- 删掉主方法内没用的代码:
- 删掉
PDDocument activeDocument = new PDDocument();声明,所有子文档都在各自方法内创建和关闭 - 删掉主文档finally里没用的空PDPageContentStream创建逻辑:
// 这两行完全没用,直接删掉 PDPageContentStream contentStream = new PDPageContentStream(doc, page, PDPageContentStream.AppendMode.APPEND, true); contentStream.close();
额外排查点
如果修改后还有问题,可以按优先级排查:
- 确认所有
PDDocument实例的关闭顺序:必须先完成所有页面导入操作,再关闭子文档,最后保存并关闭主文档 - 确认没有在
acroForm.flatten()之后再操作表单域 - 确认模板PDF文件没有损坏,读取模板的输入流没有提前关闭
内容的提问来源于stack exchange,提问作者Qassim Ali
相关产品推荐
相关产品推荐

