在Java中处理Word文档(特别是读取文本框中的文本和图片)是一个常见的需求,尤其在文档自动化、内容提取和数据分析场景中。本文将详细介绍如何使用Apache POI和docx4j这两个主流库来读取Word文档(.docx格式)中文本框内的文本和图片。
![图片[1]_Java读取Word文本框中的文本和图片的实践指南_知途无界](https://zhituwujie.com/wp-content/uploads/2025/11/d2b5ca33bd20251106092126.png)
一、Word文档结构基础
Word的.docx文件本质是一个ZIP压缩包,内部包含XML文件(如document.xml、word/media/中的图片文件)和关系定义(_rels/文件夹)。
文本框在Word中属于“浮动形状”(Floating Shape),通常嵌套在文档的“绘图层”中(通过wp:inline或wp:anchor标签定义)。
图片可能直接嵌入文本框内,或作为文本框的装饰元素,存储在文档的media目录下,并通过关系(Relationship)与文本内容关联。
二、方案一:使用Apache POI(适合基础需求)
Apache POI是Java生态中最常用的Office文档处理库,但对复杂元素(如文本框内的图片)支持有限,更适合提取文本框中的纯文本。
1. 添加依赖
Maven项目中添加以下依赖:
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.4</version> <!-- 使用最新稳定版 -->
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.4</version>
</dependency>
2. 读取文本框中的文本
文本框在POI中通过XWPFSDT(Structured Document Tag)或绘图对象(XWPFPicture关联的形状)实现,但更常见的是通过文档的“绘图层”中的CTInline或CTAnchor元素定位。
以下代码演示如何遍历文档中的所有“段落”和“文本框形状”(简化版,实际需处理复杂结构):
import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlObject;
import java.io.FileInputStream;
import java.util.List;
public class PoiReadTextBoxText {
public static void main(String[] args) throws Exception {
try (FileInputStream fis = new FileInputStream("example.docx");
XWPFDocument doc = new XWPFDocument(fis)) {
// 遍历所有段落(部分文本框文本可能出现在段落中)
for (XWPFParagraph para : doc.getParagraphs()) {
System.out.println("段落文本: " + para.getText());
}
// 遍历所有表格(文本框可能嵌套在表格中)
for (XWPFTable table : doc.getTables()) {
for (XWPFTableRow row : table.getRows()) {
for (XWPFTableCell cell : row.getTableCells()) {
for (XWPFParagraph p : cell.getParagraphs()) {
System.out.println("表格单元格文本: " + p.getText());
}
}
}
}
// 注意:POI对直接提取文本框(浮动形状)的文本支持较弱,需通过底层XML解析(见下文补充)
}
}
}
补充:通过底层XML解析文本框文本(高级)
若需直接提取文本框(浮动形状)中的文本,需操作POI的底层XML对象(CTDrawing、CTInline等)。示例代码:
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDrawing;
import org.apache.xmlbeans.XmlCursor;
// 在遍历段落时检查是否包含绘图对象(文本框)
for (XWPFParagraph para : doc.getParagraphs()) {
for (XWPFRun run : para.getRuns()) {
CTDrawing drawing = run.getCTR().getDrawingArray(0); // 获取第一个绘图对象
if (drawing != null) {
// 解析绘图对象中的文本(需进一步处理CTInline/CTPicture)
XmlCursor cursor = drawing.newCursor();
while (cursor.hasNextToken()) {
// 此处需根据实际XML结构提取文本(复杂,建议用docx4j替代)
}
}
}
}
局限性:POI对文本框内图片的提取几乎无直接支持,且文本框的XML结构复杂,推荐优先使用docx4j。
三、方案二:使用docx4j(推荐,支持文本框文本和图片)
docx4j是专为处理.docx文档设计的高级库,提供了对文本框、图片等复杂元素的完整支持,能更简单地提取文本框内的文本和图片。
1. 添加依赖
Maven项目中添加:
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j-core</artifactId>
<version>11.4.4</version> <!-- 使用最新版 -->
</dependency>
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j-export-fo</artifactId>
<version>11.4.4</version>
</dependency>
2. 读取文本框中的文本
docx4j通过org.docx4j.wml.Drawing和org.docx4j.dml.wordprocessingDrawing.Inline等类定位文本框,并提取其中的文本节点。
完整代码示例:
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.wml.*;
import org.docx4j.dml.wordprocessingDrawing.Inline;
import java.io.File;
import java.util.List;
public class Docx4jReadTextBox {
public static void main(String[] args) throws Exception {
// 加载Word文档
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new File("example.docx"));
MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart();
// 遍历文档中的所有段落
List<Object> content = documentPart.getContent();
for (Object obj : content) {
if (obj instanceof P) { // P表示段落
P paragraph = (P) obj;
for (Object runObj : paragraph.getContent()) {
if (runObj instanceof R) { // R表示运行(Run)
R run = (R) runObj;
for (Object drawingObj : run.getContent()) {
if (drawingObj instanceof Drawing) { // Drawing可能包含文本框或图片
Drawing drawing = (Drawing) drawingObj;
// 解析绘图对象中的文本框内容
extractTextBoxText(drawing);
}
}
}
}
}
}
}
// 提取文本框中的文本
private static void extractTextBoxText(Drawing drawing) {
if (drawing.getInlineArray().length > 0) {
Inline inline = drawing.getInlineArray(0); // 获取第一个内联绘图对象(文本框)
// 文本框的文本通常存储在<pict>或<t>标签中(需进一步解析)
// 此处简化:通过docx4j的辅助方法获取文本
String text = getTextFromDrawing(inline);
if (text != null && !text.trim().isEmpty()) {
System.out.println("文本框文本: " + text);
}
}
}
// 辅助方法:从绘图对象中提取文本(简化实现)
private static String getTextFromDrawing(Inline inline) {
// 实际需解析inline的XML结构(通常包含<t>标签)
// 这里使用docx4j的XmlUtils和XPath简化(需引入相关依赖)
try {
org.w3c.dom.Node node = inline.getDomNode();
// 查找<t>标签(文本节点)
// 注:实际代码需使用XPath或遍历DOM节点(示例省略复杂逻辑)
return "从绘图对象提取的文本(需实现具体解析)";
} catch (Exception e) {
return null;
}
}
}
更简单的文本框文本提取(推荐使用docx4j的org.docx4j.TextUtils)
docx4j提供了更高层的工具类TextUtils,可简化文本提取(但可能仍需处理文本框的特殊情况):
import org.docx4j.TextUtils;
import org.docx4j.wml.ContentAccessor;
// 遍历文档内容并提取所有文本(包括文本框)
String allText = TextUtils.extractText(documentPart.getContent());
System.out.println("文档所有文本(含文本框): " + allText);
注意:此方法会提取文档内所有文本(包括文本框),但无法区分文本框与其他部分的文本。若需精确提取文本框文本,仍需解析绘图对象。
3. 读取文本框中的图片
图片在Word中通过org.docx4j.wml.Drawing关联的org.docx4j.dml.Graphic和org.docx4j.dml.blipFill.Blip定义,存储在文档的media/目录下。
完整代码示例:
import org.docx4j.openpackaging.parts.Part;
import org.docx4j.openpackaging.parts.relationships.RelationshipsPart;
import org.docx4j.relationships.Relationship;
import java.io.FileOutputStream;
import java.util.List;
// 在遍历Drawing对象时提取图片
private static void extractImagesFromDrawing(Drawing drawing) {
if (drawing.getInlineArray().length > 0) {
Inline inline = drawing.getInlineArray(0);
// 获取绘图对象的关联关系(Blip指向图片)
if (inline.getGraphic() != null) {
org.docx4j.dml.Graphic graphic = inline.getGraphic();
// 解析Blip(图片引用)
// 此处简化:通过docx4j的辅助方法获取图片数据
byte[] imageData = getImageDataFromDrawing(inline);
if (imageData != null) {
try (FileOutputStream fos = new FileOutputStream("extracted_image.png")) {
fos.write(imageData);
System.out.println("图片已保存为 extracted_image.png");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
// 辅助方法:从绘图对象中提取图片数据(简化实现)
private static byte[] getImageDataFromDrawing(Inline inline) {
try {
// 获取Blip(图片引用)
org.docx4j.dml.blipFill.Blip blip = inline.getGraphic().getGraphicData()
.getAny().stream()
.filter(obj -> obj instanceof org.docx4j.dml.blipFill.BlipFillProperties)
.map(obj -> (org.docx4j.dml.blipFill.BlipFillProperties) obj)
.findFirst()
.orElse(null)
.getBlipArray(0);
if (blip != null) {
String blipId = blip.getEmbed(); // 获取图片的关联ID
// 通过文档的关系部分找到图片的实际数据
RelationshipsPart rp = inline.getPart().getRelationshipsPart();
Relationship rel = rp.getRelationship(blipId);
Part imagePart = rp.getPart(rel);
return imagePart.getInputStream().readAllBytes();
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
更简单的图片提取(推荐使用docx4j的org.docx4j.export.PictureExtractor)
docx4j提供了专门的图片提取工具类,可自动遍历文档中的所有图片(包括文本框内的图片):
import org.docx4j.export.PictureExtractor;
// 创建图片提取器
PictureExtractor pictureExtractor = new PictureExtractor(wordMLPackage);
List<org.docx4j.openpackaging.parts.Part> images = pictureExtractor.extractImages();
// 保存所有图片
int index = 1;
for (Part imagePart : images) {
String fileName = "extracted_image_" + index + ".png";
try (FileOutputStream fos = new FileOutputStream(fileName)) {
fos.write(imagePart.getInputStream().readAllBytes());
System.out.println("图片已保存: " + fileName);
} catch (Exception e) {
e.printStackTrace();
}
index++;
}
注意:此方法会提取文档内所有图片(包括文本框内和非文本框内的图片),但无法直接区分图片所属的文本框。若需精确提取文本框内的图片,需结合绘图对象的解析。
四、综合示例:完整提取文本框文本和图片(docx4j)
以下代码整合了文本框文本和图片的提取逻辑:
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.wml.*;
import org.docx4j.dml.wordprocessingDrawing.Inline;
import org.docx4j.export.PictureExtractor;
import java.io.File;
import java.util.List;
public class Docx4jFullExample {
public static void main(String[] args) throws Exception {
// 1. 加载文档
WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(new File("example.docx"));
MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart();
// 2. 提取所有文本(含文本框)
String allText = org.docx4j.TextUtils.extractText(documentPart.getContent());
System.out.println("文档所有文本(含文本框): " + allText);
// 3. 提取所有图片(含文本框内的图片)
PictureExtractor pictureExtractor = new PictureExtractor(wordMLPackage);
List<org.docx4j.openpackaging.parts.Part> images = pictureExtractor.extractImages();
int imgIndex = 1;
for (org.docx4j.openpackaging.parts.Part imagePart : images) {
String fileName = "extracted_image_" + imgIndex++ + ".png";
try (java.io.FileOutputStream fos = new java.io.FileOutputStream(fileName)) {
fos.write(imagePart.getInputStream().readAllBytes());
System.out.println("图片已保存: " + fileName);
}
}
// 4. 精确提取文本框文本和图片(需解析绘图对象,见前文补充)
}
}
五、注意事项与常见问题
- 文本框的复杂性:
Word中的文本框可能是浮动形状(Floating Shape)或嵌入式形状(Inline Shape),且可能嵌套在其他元素(如表格、页眉页脚)中。需遍历文档的所有部分(段落、表格、页眉等)。 - 图片存储位置:
图片通常存储在文档的word/media/目录下(通过ZIP解压可见),并通过关系(Relationship)与绘图对象关联。提取时需通过Blip的embed属性找到对应的图片部分。 - 库的选择建议:
- 若只需提取文本框中的纯文本,且文档结构简单,优先使用Apache POI(简单易用)。
- 若需提取文本框中的文本和图片,或处理复杂结构(如嵌套文本框),强烈推荐docx4j(功能更强大,但学习曲线稍陡)。
- 调试技巧:
- 使用工具(如7-Zip)解压.docx文件,直接查看
word/document.xml和word/media/目录,理解文档结构。 - 打印绘图对象(
Drawing)的XML内容(通过System.out.println(inline.toString())),辅助定位文本和图片的关联关系。
- 使用工具(如7-Zip)解压.docx文件,直接查看
通过上述方法,你可以灵活地在Java中提取Word文本框中的文本和图片,满足文档处理、内容迁移等实际需求。根据项目复杂度选择合适的库(POI或docx4j),并注意处理文档结构的多样性。

























暂无评论内容