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
相关产品推荐
相关产品推荐

