【问题标题】:"IOException: COSStream has been closed and cannot be read" when trying to save PDF after adding page with PdfBox使用 PdfBox 添加页面后尝试保存 PDF 时出现“IOException:COSStream 已关闭且无法读取”
【发布时间】:2026-01-23 03:40:01
【问题描述】:

我很难让这段代码正常工作。目标是将 pdf 与 PDDocument 对象中加载的 pdf 合并。我不想使用 PdfBox 的 mergeUtility 因为它意味着关闭 PDDocument 对象。我有很多数据要处理,我使用循环来处理它。加载和关闭 PDDocument 将花费太多时间和资源(也许我错了,但感觉就是这样)。

这是我的做法:

for (String path:pathList) {
    /* ... */
    if(path.endsWith("pdf")){
        File pdfToMerge = new File(path);
        try(PDDocument pdfToMergeDocument = PDDocument.load(pdfToMerge)){
            for (int pageIndex = 0; pageIndex < pdfToMergeDocument.getNumberOfPages(); pageIndex++){
                PDPage page = pdfToMergeDocument.getPage(pageIndex);
                doc.addPage(page);
            }
        }catch (IOException e){
            System.out.println("Pdf : " + path + ANSI_RED + "  [FAILED]" + ANSI_RESET);
            continue;
        }finally {
            System.out.println("Pdf : " + path + ANSI_GREEN +"  [OK]" + ANSI_RESET);
        }
    }
}
doc.save("src/Kairos/OutPut/"+pdfName[pdfName.length - 1]+".pdf");
doc.close();

当我尝试在第 65 行保存文档时发生错误。

我收到此错误消息:

Exception in thread "main" java.io.IOException: COSStream has been closed and cannot be read. Perhaps its enclosing PDDocument has been closed?
at org.apache.pdfbox.cos.COSStream.checkClosed(COSStream.java:83)
at org.apache.pdfbox.cos.COSStream.createRawInputStream(COSStream.java:133)
at org.apache.pdfbox.pdfwriter.COSWriter.visitFromStream(COSWriter.java:1214)
at org.apache.pdfbox.cos.COSStream.accept(COSStream.java:402)
at org.apache.pdfbox.cos.COSObject.accept(COSObject.java:158)
at org.apache.pdfbox.pdfwriter.COSWriter.doWriteObject(COSWriter.java:521)
at org.apache.pdfbox.pdfwriter.COSWriter.doWriteObjects(COSWriter.java:459)
at org.apache.pdfbox.pdfwriter.COSWriter.doWriteBody(COSWriter.java:443)
at org.apache.pdfbox.pdfwriter.COSWriter.visitFromDocument(COSWriter.java:1108)
at org.apache.pdfbox.cos.COSDocument.accept(COSDocument.java:449)
at org.apache.pdfbox.pdfwriter.COSWriter.write(COSWriter.java:1381)
at org.apache.pdfbox.pdfwriter.COSWriter.write(COSWriter.java:1268)
at org.apache.pdfbox.pdmodel.PDDocument.save(PDDocument.java:1334)
at org.apache.pdfbox.pdmodel.PDDocument.save(PDDocument.java:1305)
at org.apache.pdfbox.pdmodel.PDDocument.save(PDDocument.java:1293)
at Kairos.Main.main(Main.java:65)

【问题讨论】:

  • @FedericoklezCulloca doc 在文件开头声明,它是使用 apache 示例的 CreatePDFA 类创建的。我检查代码是否在没有这部分的情况下工作,一切都很好我没有收到错误,我可以保存文档。问题确实出在这个街区。如果你愿意,我可以编辑我的帖子以添加完整的代码。
  • 总结答案:仅在保存doc后关闭pdfToMergeDocument
  • @TilmanHausherr 请在下面重新阅读我的答案。那里有一个循环,在第一次迭代结束时关闭doc。在第二次迭代中,save 失败,因为 doc 已关闭。
  • 哎呀,确实。 (但我的评论可能仍然适用)
  • @TilmanHausherr 确实如此。我刚刚重新阅读了PDDocument::addPage 方法的文档。它没有说清楚,但它没有复制。我稍后会用解决方案来修改我的答案。感谢您的 cmets

标签: java merge pdfbox


【解决方案1】:

考虑一下:您在pathList 中有一个Strings 列表,然后您遍历它。

在第一个循环结束时,您保存 doc 并关闭它。

然后你再次循环并尝试保存doc。您在上一次迭代中关闭的。

如果您的目标是将 pathList 中的所有 pdf 的内容放在 doc 指向的 pdf 中,则必须在循环完所有内容后将其 在循环之外关闭pathList.

编辑:

正如 Tilman Hausherr 所指出的,还有另一个问题。当您致电addPage 时,您并没有复制原始页面,而是或多或少地链接到它。由于您使用的是 try-with-resources 构造,原始文件会在 try-catch 构造的末尾关闭,这意味着,一旦您退出构造,您就会失去对原始页面的任何引用。因此,您必须在退出try-catch 之前保存,或者使用importPage 代替,这会生成一个副本(然后无论如何都会调用addPage)。所以

PDPage page = pdfToMergeDocument.getPage(pageIndex);
doc.importPage(page);

编辑 2:

当然这个答案现在是错误的,因为 OP 在原始问题中发布了错误的代码 :) 我会留在这里以防万一有人需要它。

【讨论】:

  • 确实:您不应该在保存目标文档之前关闭源文档。因为目标文档仍然从源文档中访问资源。
  • 很抱歉,循环部分的答案不仅仅是因为我很笨。我按照文件中的方式编辑代码。但是您对答案的编辑可能是解决方案。我试试看
  • 原来doc.importPage(page);的解决方案不起作用,我的帖子出错了。
  • 然后编辑您的问题以添加新代码(不要删除旧代码)。
最近更新 更多