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.hwpf | HWPFDocument | Paragraph | CharacterRun | Office 97-2003 兼容 |
.docx (OOXML) | org.apache.poi.xwpf | XWPFDocument | XWPFParagraph | XWPFRun | Office 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();
}
}
}
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());
}
TableIterator 遍歷PicturesTable:doc.getPicturesTable().getAllPictures()| 問題 | 原因 | 解決方案 |
|---|---|---|
.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 |
| 大文件 OOM | XWPFDocument 全量載入 DOM | 使用 XWPFDocument(InputStream, true) 延遲加載;或 SAX 事件解析 (複雜) |
| 表格跨行/跨列合併單元格讀取錯誤 | POI 對合併單元格支持有限 | 獲取 ctTc.getTcPr().getGridSpan() / vMerge 手動處理 |
| .doc 文件損壞/非標準格式 | HWPF 容錯性差 | 先用 Word 另存為 .docx,再用 XWPF 解析 |
WordReader 工具類,屏蔽 .doc/.docx 差異InputStream 傳遞,避免 File 佔用句柄Apache Tika (統一接口支持 Word/PDF/Excel/PPT)總結:Apache POI 是 Java 操作 Word 唯一成熟選擇。新項目強制用 .docx + XWPF,避開 HWPF 坑點。封裝統一工具類、異步化處理、大文件流式讀取、轉 PDF 預覽,是生產級落地關鍵。純文本提取場景推薦 Apache Tika 簡化依賴。