You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iText7与html2pdf处理PDF时文档已关闭异常的解决咨询

解决iText7+html2pdf中"Document was closed"异常的方案

问题根源

HtmlConverter.convertToPdf()方法在完成HTML到PDF的转换后,会自动关闭传入的PdfDocument实例。你在splitAndCreateDocuments()中将已被关闭的PdfDocument存入Map,后续在createFinalPdf()中尝试调用getNumberOfPages()时,自然触发了文档已关闭的异常。

解决方案

方案一:转换后以只读模式重新打开PDF

修改splitAndCreateDocuments()方法,先生成临时PDF文件并关闭自动关闭的文档,再以只读模式重新打开该文件存入Map:

public Map<Integer, PdfDocument> splitAndCreateDocuments(String inputHtml) throws IOException {
    var converterProperties = new ConverterProperties();
    Map<Integer, PdfDocument> documentMap = new HashMap<>();
    String[] segments = inputHtml.split("<landscape>");

    for (int i = 1; i < segments.length; i++) {
        String segmentHtml = segments[i];
        String tempPdfPath = "temp_" + i + ".pdf";
        
        // 生成临时PDF,转换完成后文档会被自动关闭
        try (PdfDocument pdfDocument = new PdfDocument(new PdfWriter(tempPdfPath))) {
            HtmlConverter.convertToPdf(segmentHtml, pdfDocument, converterProperties);
        }
        
        // 以只读模式重新打开临时PDF,存入Map
        PdfReader reader = new PdfReader(tempPdfPath);
        PdfDocument readOnlyDoc = new PdfDocument(reader);
        documentMap.put(i, readOnlyDoc);
    }

    return documentMap;
}

同步修改createFinalPdf(),确保资源被正确释放并清理临时文件:

public void createFinalPdf(Map<Integer, PdfDocument> documentMap, String outputPath) throws IOException {
    try (PdfDocument finalPdf = new PdfDocument(new PdfWriter(outputPath));
         PdfMerger merger = new PdfMerger(finalPdf)) {

        for (Map.Entry<Integer, PdfDocument> entry : documentMap.entrySet()) {
            PdfDocument pdfDocument = entry.getValue();
            int docNrPages = pdfDocument.getNumberOfPages();
            merger.merge(pdfDocument, 1, docNrPages);
            // 关闭只读文档和对应的Reader
            pdfDocument.close();
            pdfDocument.getReader().close();
            // 删除临时PDF文件
            Files.delete(Paths.get("temp_" + entry.getKey() + ".pdf"));
        }
    }
}

方案二:使用字节流避免临时文件

如果不想生成磁盘临时文件,可通过字节流接收转换结果,再创建只读文档:

public Map<Integer, PdfDocument> splitAndCreateDocuments(String inputHtml) throws IOException {
    var converterProperties = new ConverterProperties();
    Map<Integer, PdfDocument> documentMap = new HashMap<>();
    String[] segments = inputHtml.split("<landscape>");

    for (int i = 1; i < segments.length; i++) {
        String segmentHtml = segments[i];
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        
        // 转换到字节流,转换完成后文档自动关闭
        try (PdfDocument pdfDocument = new PdfDocument(new PdfWriter(baos))) {
            HtmlConverter.convertToPdf(segmentHtml, pdfDocument, converterProperties);
        }
        
        // 从字节流创建只读文档
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        PdfReader reader = new PdfReader(bais);
        PdfDocument readOnlyDoc = new PdfDocument(reader);
        documentMap.put(i, readOnlyDoc);
    }

    return documentMap;
}

对应的createFinalPdf()只需释放资源即可:

public void createFinalPdf(Map<Integer, PdfDocument> documentMap, String outputPath) throws IOException {
    try (PdfDocument finalPdf = new PdfDocument(new PdfWriter(outputPath));
         PdfMerger merger = new PdfMerger(finalPdf)) {

        for (Map.Entry<Integer, PdfDocument> entry : documentMap.entrySet()) {
            PdfDocument pdfDocument = entry.getValue();
            int docNrPages = pdfDocument.getNumberOfPages();
            merger.merge(pdfDocument, 1, docNrPages);
            pdfDocument.close();
            pdfDocument.getReader().close();
        }
    }
}

注意事项

  • 始终确保PdfDocument和PdfReader被正确关闭,推荐使用try-with-resources语法自动管理资源,避免内存泄漏。
  • 使用临时文件方案时,务必在合并完成后删除临时文件,避免占用磁盘空间。

内容的提问来源于stack exchange,提问作者ittradco

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 22:15:24