Apache POI操作已有Word文档:新增/覆盖表格及报错解决
解决Apache POI写入Word文档时的ZLIB输入流异常
错误原因
直接对同一个文件同时执行读和写操作,OPCPackage.open打开文件后会占用文件资源,此时用FileOutputStream写入会破坏文件的压缩结构,触发EOFException: Unexpected end of ZLIB input stream异常。
解决方案
核心思路是避免读写同一文件的冲突,先将原文档读取到内存,再写入临时文件,最后替换原文件;同时处理原有内容的清除,实现第二页表格的覆盖更新。
修正后的代码
import org.apache.poi.xwpf.usermodel.*; import org.apache.poi.openxml4j.opc.OPCPackage; import java.io.*; public class WordTableUpdater { public static void main(String[] args) { String sourceFile = "Testword.docx"; String tempFile = "Temp_Testword.docx"; try (OPCPackage pkg = OPCPackage.open(new FileInputStream(sourceFile)); XWPFDocument doc = new XWPFDocument(pkg); FileOutputStream outStream = new FileOutputStream(tempFile)) { // 清除第二页及之后的原有内容(包括表格) boolean isAfterPageBreak = false; // 倒序遍历,避免索引偏移 for (int i = doc.getBodyElements().size() - 1; i >= 0; i--) { IBodyElement element = doc.getBodyElements().get(i); if (isAfterPageBreak) { doc.removeBodyElement(i); continue; } // 检查段落是否包含分页符 if (element instanceof XWPFParagraph) { XWPFParagraph para = (XWPFParagraph) element; for (XWPFRun run : para.getRuns()) { if (run.getCTR().getBrList().stream() .anyMatch(br -> br.getType() == org.openxmlformats.schemas.wordprocessingml.x2006.main.STBrType.PAGE)) { isAfterPageBreak = true; break; } } } } // 如果首页没有分页符,添加一个确保表格在第二页 if (!isAfterPageBreak) { XWPFParagraph pageBreakPara = doc.createParagraph(); XWPFRun run = pageBreakPara.createRun(); run.addBreak(BreakType.PAGE); } // 创建新表格 XWPFTable table = doc.createTable(); // 构建第一行 XWPFTableRow row1 = table.getRow(0); row1.getCell(0).setText("col one, row one"); row1.addNewTableCell().setText("col two, row one"); row1.addNewTableCell().setText("col three, row one"); // 构建第二行 XWPFTableRow row2 = table.createRow(); row2.getCell(0).setText("col one, row two"); row2.getCell(1).setText("col two, row two"); row2.getCell(2).setText("col three, row two"); // 构建第三行 XWPFTableRow row3 = table.createRow(); row3.getCell(0).setText("col one, row three"); row3.getCell(1).setText("col two, row three"); row3.getCell(2).setText("col three, row three"); // 写入临时文件 doc.write(outStream); // 替换原文件 File original = new File(sourceFile); File temp = new File(tempFile); if (original.delete() && temp.renameTo(original)) { System.out.println("表格更新完成"); } else { System.err.println("替换原文件失败,请检查文件权限"); } } catch (Exception e) { e.printStackTrace(); } } }
关键改动说明
- 读写分离:用
FileInputStream读取原文档,写入临时文件后再替换原文件,彻底避免资源冲突 - 清除原有内容:倒序遍历文档元素,找到分页符后移除后续所有内容,实现覆盖更新
- 自动资源管理:使用try-with-resources语法自动关闭流,防止资源泄漏
- 确保分页:如果首页没有分页符,自动添加一个,保证表格生成在第二页
内容的提问来源于stack exchange,提问作者Jeet
相关产品推荐
相关产品推荐

