使用XWPFDocument追加内容至Word文件时遇异常求助
帮你搞定POI操作Word的这两个问题!
先拆解下你遇到的两个核心问题:
org.apache.poi.EmptyFileException:这锅得甩给你构造函数里的writeToWord()方法!你一上来就用FileOutputStream打开目标Word文件,这操作会直接把原有文件清空成0字节,之后再去读这个空文件,POI可不就给你抛空文件异常了嘛。java.lang.NullPointerException:因为第一步文件读取失败,doc对象没初始化成功,后面的para和run自然都是null,你调用setText()的时候去访问null对象的方法,不触发空指针才怪~
下面是修复后的完整代码,我给你标了关键修改点,一眼就能看懂:
import java.awt.AWTException; import java.awt.Rectangle; import java.awt.Robot; import java.awt.Toolkit; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.xwpf.usermodel.ParagraphAlignment; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.apache.poi.xwpf.usermodel.XWPFRun; import org.apache.poi.util.Units; public class tester{ FileOutputStream fos = null; XWPFDocument doc = null; XWPFParagraph para = null; XWPFRun run = null; File file = null; public tester() { try { file = new File("WordDocWithImage.docx"); // 👉 关键修改1:先读文件再搞输出流! if (file.exists() && file.length() > 0) { // 文件存在且非空,读取现有内容 doc = new XWPFDocument(OPCPackage.open(file)); } else { // 文件不存在/为空,新建文档 doc = new XWPFDocument(); } para = doc.createParagraph(); run = para.createRun(); para.setAlignment(ParagraphAlignment.CENTER); } catch (Exception e) { e.printStackTrace(); System.out.println("failed to create file"); } } // 👉 关键修改2:输出流挪到最后再创建,别提前清空文件! public void prepareOutputStream() throws FileNotFoundException { fos = new FileOutputStream("WordDocWithImage.docx"); } public void setText(String text) { // 👉 加个空判断,防止初始化失败崩掉 if (run != null) { run.setText(text); } } public void takeScreenshot() throws IOException, AWTException, InvalidFormatException { if (run == null) { throw new IllegalStateException("Run对象没初始化好哦,先检查文件读取逻辑~"); } Robot robot = new Robot(); Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()); BufferedImage screenFullImage = robot.createScreenCapture(screenRect); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageIO.write(screenFullImage, "jpeg", baos); baos.flush(); ByteArrayInputStream bis = new ByteArrayInputStream(baos.toByteArray()); run.addBreak(); run.addPicture(bis, XWPFDocument.PICTURE_TYPE_JPEG, "image file", Units.toEMU(450), Units.toEMU(250)); bis.close(); baos.close(); } public void writeToFile() { try { if (doc != null && fos != null) { doc.write(fos); fos.close(); } } catch (Exception e) { e.printStackTrace(); } } public static void main(String[] args) { tester t = new tester(); try { System.out.println("Taking first ss"); t.setText("First Text"); t.takeScreenshot(); System.out.println("Taking second ss"); t.setText("Second Text"); t.takeScreenshot(); // 👉 关键修改3:最后再准备输出流写入,避免提前清空文件 t.prepareOutputStream(); t.writeToFile(); } catch(Exception e) { e.printStackTrace(); } } }
核心修改要点总结:
- 调整文件操作顺序:先检查并读取现有文件(存在且非空的话),绝对不能先开输出流清空文件,不然读的时候直接凉透。
- 重构输出流逻辑:把输出流的创建移到所有内容都准备好之后,最后写入文件的时候再操作,这样不会破坏原有文件内容。
- 加空指针防护:在使用
run这类关键对象前先判断非空,就算初始化出问题也不会直接崩掉,还能给你明确的提示。 - 优化资源管理:确保各种流都正确关闭,避免内存泄漏。
这样改完之后,不管是给现有Word文件追加内容,还是文件不存在时新建文件,都能正常工作啦~
内容的提问来源于stack exchange,提问作者Ashraf Mulla
相关产品推荐
相关产品推荐

