java解析word文档
本文介绍了使用Apache POI库处理Word文档的方法,重点包括段落样式和图片的读取。在段落处理方面,展示了如何获取文本内容、首行缩进、字体颜色和大小等样式属性,并指出了API存在的空指针异常问题及解决方法。在图片处理部分,详细列出了Word支持的11种图片格式及其特点,提供了读取图片数据的代码示例。文章还深入分析了Word底层XML结构,指出了Apache POI在封装上的不足,需要开发者直
文章目录
读取段落
使用document.getParagraphs()可以获取所有段落,读取段落文本内容可以使用paragraph.getText()。
但是细节的获取也很关键。以下是常见API:
| API | 用途 |
|---|---|
| XWPFParagraph#getFirstLineIndent | 获取首行缩进 |
| XWPFRun#getColor | 获取文字颜色 |
| XWPFRun#getFontFamily | 获取字体 |
| XWPFRun#getFontSizeAsDouble | 获取字体大小 |
以下是一个完整的例子:
public class Main {
public static void main(String[] args) {
try (FileInputStream stream = new FileInputStream("pages.docx")) {
XWPFDocument document = new XWPFDocument(stream);
List<XWPFParagraph> paragraphs = document.getParagraphs();
for (XWPFParagraph paragraph : paragraphs) {
System.out.println(paragraph.getText());
List<XWPFRun> runs = paragraph.getRuns();
int firstLineIndent = paragraph.getFirstLineIndent();
System.out.printf("段落首行缩进为"+firstLineIndent);
for (XWPFRun run : runs) {
String color = run.getColor();
String fontFamily = run.getFontFamily();
Double fontSizeAsDouble = run.getFontSizeAsDouble();
System.out.println("文字颜色为" + color + ",字体为" + fontFamily+",字号"+fontSizeAsDouble);
}
}
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
style数组为空的问题
如果没有显式设置字号,那么XWPFRun#getFontSizeAsDouble就会返回null。如果我们想从这个run的style中得到字体大小,在apache poi 5.0.0的代码中,是有bug的。代码位于XWPFRun#getStyle:
public String getStyle() {
CTRPr pr = getCTR().getRPr();
if (pr == null) {
return "";
}
CTString style = pr.getRStyleArray(0);
if (style == null) {
return "";
}
return style.getVal();
}
运行时会触发空指针异常:
Exception in thread “main” java.lang.IndexOutOfBoundsException
at org.openxmlformats.schemas.wordprocessingml.x2006.main.impl.CTRPrImpl.getRStyleArray(CTRPrImpl.java:160)
at org.apache.poi.xwpf.usermodel.XWPFRun.getStyle(XWPFRun.java:1256)
at cn.edu.ncepu.Main.getFontSizeAsDouble(Main.java:55)
at cn.edu.ncepu.Main.main(Main.java:38)
但是在最新的版本5.2.4中已经修复了这个空指针的bug。但是获取了style之后依然难,因为word的style是一个继承关系,而且有很多默认值。
从rpr里获取字体字号
apache poi目前还不完善,没有直接从style中获取字号的api,所以我们直接从style的rpr元素中取。比如以下代码:
private static Double getFontSize(XWPFStyle xwpfStyle) {
CTRPr rPr = (xwpfStyle.getCTStyle()).getRPr();
if (rPr.getSzArray().length > 0) {
return ((BigInteger) rPr.getSzArray(0).getVal()).doubleValue();
}
return null;
}
word的rpr里包含了字体的定义,。假如样式里定义了字体,那么就可以用rPr.getRFontsArray(0).getEastAsia()来获取字体。如果自身没有定义,那么字体字号的定义就来自继承的样式,可以使用xwpfStyle.getBasisStyleID()来获取继承的样式id。rpr非常复杂,下面我简单介绍一些常用的rpr属性:
| POI API | RPR XML元素 | 用途 |
|---|---|---|
| rPr.getRFontsArray(0) | <w:rFonts w:eastAsia=“隶书”/> | 定义字体 |
| rPr.getBArray() | <w:b/> | 字体加粗 |
| rPr.getUArray() | <w:u w:val=“single”/> | 字体下划线 |
| rPr.getIArray() | <w:i/> | 斜体 |
| rPr.getColorArray(0) | <w:color w:val=“EE0000”/> | 字体颜色 |
| rPr.getSzArray(0) | <w:sz w:val=“28”/> | 字号定义 |
之所以都是array,是因为word可以给不同的语言定义不同的字体,比如东亚文字和拉丁文字用不同的颜色。这样给编程增加了不少难度,同时也暴露了apache poi的诸多不足,封装太少了,需要深入研究底层xml。
读取图片
读取word里的图片也不难了,只需要获取XWPFPictureData对象就可以了,然后就可以获取到图片内容的byte数组。但是需要注意的是图片是分类型的,不要拿到图片就存为PNG!以下是word支持的图片类型,图片类型在Document类中有静态常量定义:
| 格式 | 全称 | 说明与应用场景 |
|---|---|---|
| EMF | Enhanced Metafile | Windows 增强型图元文件。矢量图形格式,放大不失真,常用于 Office 中的图表或从 Illustrator 等软件复制的矢量图。 |
| WMF | Windows Metafile | Windows 图元文件。较老的矢量/光栅混合图形格式,常用于早期的剪贴画或简单的图形。 |
| PICT | Macintosh Picture | Mac 绘图文件。主要用于早期的 Macintosh 系统,在跨平台文档中偶尔可见,包含矢量和位图数据。 |
| JPEG | Joint Photographic Experts Group | 联合图像专家组格式。最常见的有损压缩格式,适用于照片、风景等色彩丰富的图片,文件体积较小。 |
| PNG | Portable Network Graphics | 可移植网络图形。无损压缩格式,支持透明通道(Alpha),适用于网页图标、线条图或需要透明背景的图片。 |
| DIB | Device-Independent Bitmap | 与设备无关的位图。通常指标准的 Windows 位图数据,不包含文件头信息,常在剪贴板操作中出现。 |
| GIF | Graphics Interchange Format | 图形交换格式。支持 256 色,支持动画,常用于简单的网络表情包或小动画。 |
| TIFF | Tagged Image File Format | 标签图像文件格式。一种灵活的位图格式,支持无损压缩,常用于出版印刷、扫描仪存档,文件通常较大。 |
| EPS | Encapsulated PostScript | 封装的 PostScript。主要用于印刷和出版行业的矢量格式,包含一个低分辨率的预览图和高分辨率的打印指令。 |
| BMP | Bitmap | 位图文件。Windows 原生格式,通常不压缩,画质高但文件体积巨大,适合在 Windows 内部进行快速渲染。 |
| WPG | WordPerfect Graphic | WordPerfect 图元文件。一种较老的矢量图形格式,主要用于 Corel WordPerfect 文档,兼容性相对较差。 |
public static void main(String[] args) {
try(FileInputStream stream = new FileInputStream("parse/pages.docx")) {
XWPFDocument document = new XWPFDocument(stream);
List<XWPFPictureData> allPictures = document.getAllPictures();
for (XWPFPictureData pictureData: allPictures) {
byte[] data = pictureData.getData();
File file = new File(pictureData.getFileName());
Files.write(file.toPath(), data);
}
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
读取表格内容
word中的表格,是XWPFTable-XWPFTableRow-XWPFTableCell的三级结构。有个这个三级结构,就非常好写代码获取了。
public static void main(String[] args) {
try(FileInputStream stream = new FileInputStream("parse/table.docx")) {
XWPFDocument document = new XWPFDocument(stream);
List<XWPFTable> tables = document.getTables();
for (XWPFTable table: tables) {
List<XWPFTableRow> rows = table.getRows();
for (XWPFTableRow row: rows) {
List<XWPFTableCell> tableCells = row.getTableCells();
for (XWPFTableCell cell: tableCells) {
System.out.print(cell.getText());
System.out.print("\t");
}
System.out.println();
}
}
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
页码
实际工作中,解析word的场景少,生成word的场景多。但是如果有个需求是获取word特定一页的内容呢?比如说获取第9页内容,怎么办?可以说非常难实现,因为apache poi只能读取word底层的xml模型,实际的页码需要渲染才知道。
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐
所有评论(0)