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

Apache POI XWPF读取Word文档时为何无法正确获取字号?

解决Apache POI XWPF获取缺失字号的问题

问题原因

  • Word文档中,当文本片段的字号与上下文(或段落默认样式)一致时,会自动省略<sz>和<szCs>标签。POI直接调用getFontSize()等方法时,因找不到对应标签,会返回默认的-1或null。
  • 你提到的Normal样式里的<sz w:val="24">是Word的半点数(1磅=2半点数),对应显示的12磅字号,但POI的getDefaultParagraphStyle()默认仅处理段落格式(如间距),不会直接提取其中的字符样式(字号属于字符样式范畴)。

解决方案

要正确获取继承的字号,可通过两种方式处理:

方法1:从默认段落样式中提取字号

直接解析Normal样式的字符属性,获取预设字号:

String fileName = "C:\\<yourFile>.docx";
try (XWPFDocument doc = new XWPFDocument(Files.newInputStream(Paths.get(fileName)))) {
    // 获取Normal默认样式
    XWPFStyle normalStyle = doc.getStyles().getStyle("Normal");
    Integer defaultFontSize = null;
    if (normalStyle != null) {
        CTRPr styleRPr = normalStyle.getCTStyle().getRPr();
        if (styleRPr != null && styleRPr.isSetSz()) {
            // 半点数转磅值,除以2得到实际显示的字号
            defaultFontSize = styleRPr.getSz().getVal().intValue() / 2;
        }
    }

    List<XWPFParagraph> paragraphs = doc.getParagraphs();
    for (XWPFParagraph paragraph : paragraphs) {
        List<XWPFRun> runs = paragraph.getRuns();
        for (XWPFRun run : runs) {
            System.out.print(run.getText(0));
            System.out.print("| name : " + run.getFontName());
            
            // 优先用当前Run的字号,无效则用默认样式字号
            int currentSize = run.getFontSize();
            if (currentSize == -1) {
                System.out.print("| size : " + defaultFontSize);
            } else {
                System.out.print("| size : " + currentSize);
            }
            
            Double currentSizeD = run.getFontSizeAsDouble();
            if (currentSizeD == null) {
                System.out.print("| sizeD : " + (double)defaultFontSize);
            } else {
                System.out.print("| sizeD : " + currentSizeD);
            }
            
            System.out.print("| sizeC : " + run.getComplexScriptFontSizeAsDouble());
            System.out.println();
        }
    }
} catch (IOException e) {
    throw new RuntimeException(e);
}

方法2:追溯上下文的有效字号

如果文档按显示特征分段,后续无字号标签的Run会继承前一个同特征Run的字号,可维护变量记录最近的有效字号:

String fileName = "C:\\<yourFile>.docx";
try (XWPFDocument doc = new XWPFDocument(Files.newInputStream(Paths.get(fileName)))) {
    // 初始化默认字号,从Normal样式获取
    Integer lastValidFontSize = null;
    XWPFStyle normalStyle = doc.getStyles().getStyle("Normal");
    if (normalStyle != null && normalStyle.getCTStyle().getRPr() != null && normalStyle.getCTStyle().getRPr().isSetSz()) {
        lastValidFontSize = normalStyle.getCTStyle().getRPr().getSz().getVal().intValue() / 2;
    }

    List<XWPFParagraph> paragraphs = doc.getParagraphs();
    for (XWPFParagraph paragraph : paragraphs) {
        List<XWPFRun> runs = paragraph.getRuns();
        for (XWPFRun run : runs) {
            System.out.print(run.getText(0));
            System.out.print("| name : " + run.getFontName());
            
            int currentSize = run.getFontSize();
            if (currentSize == -1) {
                System.out.print("| size : " + lastValidFontSize);
            } else {
                System.out.print("| size : " + currentSize);
                // 更新最近的有效字号
                lastValidFontSize = currentSize;
            }
            
            Double currentSizeD = run.getFontSizeAsDouble();
            if (currentSizeD == null) {
                System.out.print("| sizeD : " + (double)lastValidFontSize);
            } else {
                System.out.print("| sizeD : " + currentSizeD);
                lastValidFontSize = currentSizeD.intValue();
            }
            
            System.out.print("| sizeC : " + run.getComplexScriptFontSizeAsDouble());
            System.out.println();
        }
    }
} catch (IOException e) {
    throw new RuntimeException(e);
}

补充说明

  • POI的getDefaultRunStyle()返回的是文档全局默认字符样式,而非段落样式中的字符格式,因此无法获取Normal样式里的字号。
  • Word中字号以半点数存储,需除以2转换为用户可见的磅值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 03:13:19