You need to enable JavaScript to run this app. 如何使用Apache POI向现有docx文件插入图片,解决文件无法读取报错
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Apache POI向现有docx文件插入图片,解决文件无法读取报错

问题原因
  • 核心触发原因:若你使用的原始docx文件从未插入过PNG格式图片,Apache POI向现有文档插入PNG图片时,不会自动在[Content_Types].xml配置文件中添加PNG格式的映射规则,导致Word无法识别插入的图片,判定文件损坏不可读。新建文档时POI会自动初始化所有常用图片格式的映射,所以新建文档插入图片不会报错。
  • 代码逻辑问题:你当前将同一段落内所有run的文本拼接后清空全部run,仅在最后一个run输出内容,会丢失原有run的格式(如粗体、颜色、字号等),且插入图片时没有处理[Signature]占位符之外的剩余文本内容。
  • IO流管理问题:创建XWPFDocument时使用的文件输入流未显式关闭,可能引发文件资源泄漏。
修复方案

首先手动添加PNG格式映射解决文件损坏问题,再修正替换逻辑、规范流管理即可,修复后代码如下:

// 文档读写入口逻辑,使用try-with-resources自动关闭流
try (FileInputStream fis = new FileInputStream(inputURL);
     XWPFDocument doc = new XWPFDocument(fis)) {
    // 手动注册PNG格式映射,解决现有文档无PNG配置的核心问题
    OPCPackage opcPackage = doc.getPackage();
    if (!opcPackage.getContentTypeManager().isContentTypeRegistered("png")) {
        opcPackage.getContentTypeManager().addDefaultContentType("png", "image/png");
    }
    replaceFields(doc, replacings);
    // 输出生成的文档
    try (FileOutputStream fos = new FileOutputStream(outputURL)) {
        doc.write(fos);
    }
} catch (Exception e) {
    e.printStackTrace();
}

public static void replaceFields(XWPFDocument doc, HashMap<String, String> replacings) throws IOException, InvalidFormatException {
    int pCounter = 0;
    for (XWPFParagraph p : doc.getParagraphs()) {
        pCounter++;
        List<XWPFRun> runs = p.getRuns();
        if (runs == null || runs.isEmpty()) continue;
        // 拼接整段完整文本
        StringBuilder fullText = new StringBuilder();
        for (XWPFRun run : runs) {
            fullText.append(run.text());
        }
        String processedText = fullText.toString();
        // 执行普通占位符替换
        for (String key : replacings.keySet()) {
            String value = replacings.get(key);
            if (value.isEmpty()) {
                processedText = processedText.replace(key + " ", "").replace(key, "");
            } else {
                processedText = processedText.replace(key, value);
            }
        }
        // 清空原有全部run
        for (int i = runs.size() - 1; i >= 0; i--) {
            p.removeRun(i);
        }
        // 处理签名占位符
        if (processedText.contains("[Signature]")) {
            String[] parts = processedText.split("\\[Signature\\]", 2);
            // 插入占位符前的文本
            if (!parts[0].isEmpty()) {
                XWPFRun preRun = p.createRun();
                preRun.setText(parts[0]);
            }
            // 插入签名图片
            XWPFRun imgRun = p.createRun();
            String signatureFile = "C:\\Users\\rick.van.baalen\\Downloads\\Prodin_Templates\\Signature_RVB.png";
            try (InputStream is = new FileInputStream(signatureFile)) {
                imgRun.addPicture(is, XWPFDocument.PICTURE_TYPE_PNG, signatureFile, Units.toEMU(80), Units.toEMU(65));
            }
            // 插入占位符后的文本
            if (parts.length > 1 && !parts[1].isEmpty()) {
                XWPFRun postRun = p.createRun();
                postRun.setText(parts[1]);
            }
        } else {
            // 无签名占位符直接输出替换后的文本
            XWPFRun newRun = p.createRun();
            newRun.setText(processedText);
        }
        System.out.println("Line " + pCounter + ": " + processedText);
    }
}
补充说明

如果使用的Apache POI版本低于4.1.2,建议升级到4.1.2或5.x稳定版本,旧版本存在多个插入图片相关的已知BUG,也可能导致文件损坏。如果需要保留原有段落的格式,可以在创建新run时复制原有run的格式属性即可。

内容的提问来源于stack exchange,提问作者Rick van Baalen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.15 23:54:02