| 格式 | 副檔名 | POI 組件 | 核心類 | 最低 POI 版本 |
| OLE2 二進制 | .doc | HWPF | WordExtractor, HWPFDocument | 3.5+ |
| OOXML | .docx | XWPF | XWPFWordExtractor, XWPFDocument | 3.5+ |
Maven 依賴配置
<dependencies>
<!-- 核心,兩種格式都需要 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.3.0</version> <!-- 檢查最新版 -->
</dependency>
<!-- .doc 專用 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>5.3.0</version>
</dependency>
<!-- .docx 專用 (含傳遞依賴: ooxml-schemas, xmlbeans, curvesapi) -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.3.0</version>
</dependency>
</dependencies>
注意:POI 5.0+ 需 JDK 8+,poi-ooxml 已整合 ooxml-schemas、xmlbeans 等傳遞依賴,無需手動添加。
統一讀取文本內容代碼
import org.apache.poi.POIXMLTextExtractor;
import org.apache.poi.hwpf.extractor.WordExtractor;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import java.io.*;
public class WordTextExtractor {
/** 自動偵測 .doc/.docx 並提取純文本 */
public static String extractText(File file) throws Exception {
String fileName = file.getName().toLowerCase();
try (InputStream is = new FileInputStream(file)) {
if (fileName.endsWith(".doc")) {
// HWPF (.doc)
WordExtractor extractor = new WordExtractor(is);
return extractor.getText();
} else if (fileName.endsWith(".docx")) {
// XWPF (.docx)
OPCPackage pkg = OPCPackage.open(is);
POIXMLTextExtractor extractor = new XWPFWordExtractor(pkg);
return extractor.getText();
} else {
throw new IllegalArgumentException("不支援格式: " + fileName);
}
}
}
public static void main(String[] args) {
File docFile = new File("test.doc");
File docxFile = new File("test.docx");
try {
if (docFile.exists()) {
System.out.println("=== .doc 內容 ===");
System.out.println(extractText(docFile));
}
if (docxFile.exists()) {
System.out.println("=== .docx 內容 ===");
System.out.println(extractText(docxFile));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
進階:結構化解析(段落、表格、樣式、圖片)
.docx (XWPF) 結構化讀取
import org.apache.poi.xwpf.usermodel.*;
import java.util.List;
public class DocxStructuredParser {
public static void parse(File file) throws Exception {
try (XWPFDocument doc = new XWPFDocument(OPCPackage.open(file))) {
// 1. 段落與樣式
for (XWPFParagraph para : doc.getParagraphs()) {
System.out.println("段落樣式: " + para.getStyleID());
for (XWPFRun run : para.getRuns()) {
System.out.printf(" 文字: '%s' | 粗體: %s | 字體: %s | 大小: %s%n",
run.getText(0), run.isBold(), run.getFontFamily(), run.getFontSize());
}
}
// 2. 表格
for (XWPFTable table : doc.getTables()) {
System.out.println("發現表格,行數: " + table.getNumberOfRows());
for (XWPFTableRow row : table.getRows()) {
for (XWPFTableCell cell : row.getTableCells()) {
System.out.print("[" + cell.getText() + "] ");
}
System.out.println();
}
}
// 3. 圖片 (關聯關係)
for (XWPFParagraph para : doc.getParagraphs()) {
for (XWPFRun run : para.getRuns()) {
List pics = run.getEmbeddedPictures();
for (XWPFPictureData pic : pics) {
System.out.println("圖片: " + pic.getFileName() + ", 大小: " + pic.getData().length + " bytes");
// Files.write(Paths.get(pic.getFileName()), pic.getData());
}
}
}
}
}
}
.doc (HWPF) 結構化讀取(功能較弱)
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.usermodel.*;
public class DocStructuredParser {
public static void parse(File file) throws Exception {
try (HWPFDocument doc = new HWPFDocument(new FileInputStream(file))) {
Range range = doc.getRange();
// 段落
for (int i = 0; i < range.numParagraphs(); i++) {
Paragraph para = range.getParagraph(i);
System.out.println("段落 " + i + ": " + para.text());
}
// 表格 (HWPF 表格支援有限)
TableIterator it = new TableIterator(range);
while (it.hasNext()) {
Table table = it.next();
System.out.println("表格行數: " + table.numRows());
}
}
}
}
常見坑點與解決方案
| 問題 | 原因 | 解決 |
| .docx 表格內容出現在文本末尾 | XWPFWordExtractor 先輸出段落再輸出表格 | 用 XWPFDocument 結構化遍歷,按文檔順序處理 |
| 圖片無法提取 | .doc 圖片提取極困難;.docx 需遍歷 Run 的 embeddedPictures | 接受 .doc 圖片提取限制,.docx 用上述代碼 |
| 中文亂碼 | 字體缺失或編碼問題 | 確保系統安裝中文字體,POI 5.0+ 內建字體處理改善 |
| 大檔案 OOM | 完整載入 DOM 模型 | .docx 用 SAX 事件驅動 (XWPFDocument 不支援),或分頁處理 |
| 密碼保護文檔 | 加密文檔無法直接讀取 | 用 Decryptor (POI 3.17+) 或先移除密碼 |
| 依賴衝突 (xmlbeans/ooxml-schemas) | 多版本 POI 混用 | 統一 POI 版本,排除傳遞依賴衝突 |
替代方案比較
| 方案 | 優點 | 缺點 | 適用場景 |
| Apache POI | 功能最全、社群活躍、純 Java | 記憶體佔用大、API 複雜 | 通用 Java 專案 |
| Apache Tika | 統一介面支援 1000+ 格式、自動偵測 | 底層仍用 POI、細節控制力弱 | 內容索引、全文搜尋、多格式批次處理 |
| Aspose.Words | 商業級、渲染精準、功能極強 | 收費、License 成本高 | 企業級報表、列印、轉 PDF 需求 |
| LibreOffice + CLI | 完美渲染、支援所有格式 | 需安裝 LibreOffice、啟動慢、非純 Java | 服務端轉檔服務、批次轉 PDF |
總結
- 純文本提取:用
WordExtractor / XWPFWordExtractor 最簡單。
- 結構化解析:.docx 用 XWPFDocument 功能完整;.doc 用 HWPF 受限。
- 大檔案/高併發:考慮 Tika 或 LibreOffice 轉檔服務分流。
- 依賴管理:POI 5.0+ 只需
poi、poi-scratchpad、poi-ooxml 三個核心模組。
- 上一篇文章: Java JDBC 資料庫操作完整入門:六大步驟、MySQL 實戰與資源管理最佳實踐
- 下一篇文章: CentOS 環境下 Java 安裝驗證與 JAR 包運行指南
Copyright ©
程式碼之家 All Rights Reserved