首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 讀取 Word 文檔實戰:Apache POI HWPF/XWPF 完整教程

     編輯:Java 相關知識

Java 操作 Word 文檔主流方案是 Apache POI,支持舊格式 .doc (HWPF) 和新格式 .docx (XWPF)。本文詳述環境搭建、核心 API、文本提取、段落/表格/圖片解析、常見坑點,並提供生產級工具類封裝。

一、依賴配置

<!-- Maven 坐標 (POI 5.2+ 推薦) -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>5.3.0</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.3.0</version>
</dependency>
<!-- .docx 解析需額外依賴 -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml-full</artifactId>
    <version>5.3.0</version>
</dependency>

版本說明:POI 4.x+ 需 Java 8+;POI 5.x+ 需 Java 11+。舊專案用 POI 3.17 兼容 Java 6/7。

二、核心類架構

格式包前綴文檔類段落類運行文類適用場景
.doc (二進制)org.apache.poi.hwpfHWPFDocumentParagraphCharacterRunOffice 97-2003 兼容
.docx (OOXML)org.apache.poi.xwpfXWPFDocumentXWPFParagraphXWPFRunOffice 2007+ 標準,功能更強

三、統一文本提取工具類

package com.util;

import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.extractor.WordExtractor;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFDocument;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class WordReader {

    /**
     * 讀取 Word 文檔純文本內容(自動識別 .doc/.docx)
     */
    public static String extractText(File file) throws IOException {
        try (InputStream is = new FileInputStream(file)) {
            return extractText(is, file.getName());
        }
    }

    public static String extractText(InputStream is, String fileName) throws IOException {
        if (fileName.toLowerCase().endsWith(".docx")) {
            return extractDocxText(is);
        } else if (fileName.toLowerCase().endsWith(".doc")) {
            return extractDocText(is);
        } else {
            throw new IllegalArgumentException("不支持的文件格式:" + fileName);
        }
    }

    private static String extractDocxText(InputStream is) throws IOException {
        try (XWPFDocument doc = new XWPFDocument(is);
             XWPFWordExtractor extractor = new XWPFWordExtractor(doc)) {
            return extractor.getText();
        }
    }

    private static String extractDocText(InputStream is) throws IOException {
        try (HWPFDocument doc = new HWPFDocument(is);
             WordExtractor extractor = new WordExtractor(doc)) {
            return extractor.getText();
        }
    }

    /**
     * 保留段落結構的文本提取(僅 .docx)
     */
    public static String extractTextWithParagraphs(File file) throws IOException {
        if (!file.getName().toLowerCase().endsWith(".docx")) {
            return extractText(file); // .doc 降級
        }
        try (FileInputStream fis = new FileInputStream(file);
             XWPFDocument doc = new XWPFDocument(fis)) {
            StringBuilder sb = new StringBuilder();
            for (XWPFParagraph para : doc.getParagraphs()) {
                String text = para.getText();
                if (text != null && !text.trim().isEmpty()) {
                    sb.append(text).append("\n");
                }
            }
            return sb.toString();
        }
    }
}

四、進階解析:段落、表格、圖片、樣式

.docx (XWPF) 完整解析示例

try (XWPFDocument doc = new XWPFDocument(new FileInputStream("report.docx"))) {

    // 1. 段落與樣式
    for (XWPFParagraph para : doc.getParagraphs()) {
        System.out.println("段落樣式: " + para.getStyleID());
        System.out.println("對齊方式: " + para.getAlignment());
        for (XWPFRun run : para.getRuns()) {
            System.out.printf("文本: %s | 字體: %s | 大小: %d | 粗體: %b | 顏色: %s%n",
                run.getText(0),
                run.getFontFamily(),
                run.getFontSize(),
                run.isBold(),
                run.getColor()
            );
        }
    }

    // 2. 表格解析
    for (XWPFTable table : doc.getTables()) {
        for (XWPFTableRow row : table.getRows()) {
            for (XWPFTableCell cell : row.getTableCells()) {
                System.out.print("[" + cell.getText() + "] ");
            }
            System.out.println();
        }
    }

    // 3. 圖片提取
    for (PackagePart part : doc.getPackage().getParts()) {
        if (part.getContentType().toString().startsWith("image/")) {
            try (InputStream imgIs = part.getInputStream()) {
                // 保存圖片...
                Files.copy(imgIs, Paths.get("images", part.getPartName().getName()));
            }
        }
    }

    // 4. 文檔屬性
    System.out.println("標題: " + doc.getProperties().getCoreProperties().getTitle());
    System.out.println("作者: " + doc.getProperties().getCoreProperties().getCreator());
}

.doc (HWPF) 解析差異

  • 無直接表格 API,需通過 TableIterator 遍歷
  • 圖片提取需用 PicturesTable:doc.getPicturesTable().getAllPictures()
  • 樣式解析較弱,建議轉 .docx 後處理

五、常見坑點與解決方案

問題原因解決方案
.docx 解析報 NoClassDefFoundError: org/openxmlformats/...缺少 poi-ooxml-full 或 ooxml-schemas添加 poi-ooxml-full 依賴 (POI 5.x) 或 ooxml-schemas-1.4.jar (POI 4.x)
中文亂碼/顯示方框字體未嵌入/系統缺字體確保服務器安裝中文字體;POI 僅讀取文本,渲染需轉 PDF
大文件 OOMXWPFDocument 全量載入 DOM使用 XWPFDocument(InputStream, true) 延遲加載;或 SAX 事件解析 (複雜)
表格跨行/跨列合併單元格讀取錯誤POI 對合併單元格支持有限獲取 ctTc.getTcPr().getGridSpan() / vMerge 手動處理
.doc 文件損壞/非標準格式HWPF 容錯性差先用 Word 另存為 .docx,再用 XWPF 解析

六、生產環境最佳實踐

  1. 統一入口:封裝 WordReader 工具類,屏蔽 .doc/.docx 差異
  2. 流式處理:大文件用 InputStream 傳遞,避免 File 佔用句柄
  3. 異步解析:解析耗時長,納入任務佇列,避免阻塞 Web 線程
  4. 臨時文件清理:上傳解析後及時刪除臨時文件
  5. 轉 PDF 預覽:需求複雜排版預覽時,用 LibreOffice/OnlyOffice 轉 PDF,前端用 PDF.js 渲染
  6. 替代方案評估:純文本提取可考慮 Apache Tika (統一接口支持 Word/PDF/Excel/PPT)

總結:Apache POI 是 Java 操作 Word 唯一成熟選擇。新項目強制用 .docx + XWPF,避開 HWPF 坑點。封裝統一工具類、異步化處理、大文件流式讀取、轉 PDF 預覽,是生產級落地關鍵。純文本提取場景推薦 Apache Tika 簡化依賴。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved