一、前景
在使用java poi读取.doc文件,遇到审阅 修订 功能时,poi 不能读取修定状态为“最终状态”的数据,而是读取了所有修定内容,如下图所示:
- 文本读取内容:
- 正确内容:
二、POI 类结构分析
- 根据 官网API 我们知道 poi 读取.doc 有三个主要的类:
- HWPFDocument:这个类包含了所有.doc文件的结构支持。
- HWPFDocumentCore:这个类包含了 Word 文档的大部分核心基本功能,但是没有一些表结构信息
- HWPFOldDocument:为旧文件(Word 6/Word 95)提供非常简单的支持。
- 类结构 关键点思维导图分析
三、代码解决
1、maven 依赖
点击查看代码
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>4.1.2</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.2</version>
</dependency>
2、关键代码
点击查看代码
import com.ygsoft.rpa.scene.word.WordConst;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.usermodel.*;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* .doc类的文档读取(文本与表格数据)
* jalan.wang
* http://www.jalan.wang
*/
public class WordDoc {
private final Range range;
private final List<Table> allTables = new ArrayList<>();
public WordDoc(File file) throws IOException {
// 处理doc格式 即office2003版本
POIFSFileSystem pfs = new POIFSFileSystem(file, true);
HWPFDocument hwpf = new HWPFDocument(pfs);
range = hwpf.getRange();//得到文档的读取范围
TableIterator tables = new TableIterator(range);
while (tables.hasNext()) {
Table table = tables.next();
allTables.add(table);
}
}
public String readParagraphContent() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < range.numParagraphs(); i++) {
Paragraph paragraph = range.getParagraph(i);
//如果段落 是在 table中 就跳过,此处只处理普通文本内容
if (paragraph.isInTable())
continue;
String value = getFinishValue(paragraph);
if (StringUtils.isBlank(value))
continue;
sb.append(value).append("\r\n");
}
System.out.println(sb);
return sb.toString();
}
public void readTable() {
List<String> rows = new ArrayList<>();
for (Table table : allTables) {
//迭代行,默认从0开始,可以依据需要设置i的值,改变起始行数,也可设置读取到那行,只需修改循环的判断条件即可
for (int rowIndex = 0; rowIndex < table.numRows(); rowIndex++) {
TableRow tr = table.getRow(rowIndex);
String rowValue = getRowValue(tr, rowIndex);
rows.add(rowValue);
}
}
System.out.println(String.join("\r\n", rows));
}
private String getRowValue(TableRow tr, int rowIndex) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < tr.numCells(); i++) {
TableCell td = tr.getCell(i);//取得单元格
Paragraph paragraph = td.getParagraph(0);
String value = getFinishValue(paragraph);
//去除后面的特殊符号
if (StringUtils.isNotBlank(value)) {
value = value.substring(0, value.length() - 1);
}
sb.append(value).append("[").append(rowIndex).append(",").append(i).append("]").append(" ");
}
return sb.toString();
}
/**
* 获取Doc 审阅模式下,修订:最终状态 数据
*
* @param paragraph 文本段落
* @return 返回 修订:最终状态 数据
*/
@NotNull
private String getFinishValue(Paragraph paragraph) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < paragraph.numCharacterRuns(); i++) {
CharacterRun run = paragraph.getCharacterRun(i);
//如果当前字符块 是一个删除标记,就跳过,只取最终修订版内容
if (run.isMarkedDeleted())
continue;
String value = run.text();
value = value.replace(WordConst.BLANK_CN, WordConst.BLANK).replace(WordConst.BLANK_EN, WordConst.BLANK);
if (StringUtils.isBlank(value)) continue;
sb.append(value);
}
return sb.toString();
}
public static void main(String[] args) throws Exception {
File file = new File("E:\\Users\\desktop\\测试带修订内容的文档.doc");
WordDoc wordDoc = new WordDoc(file);
wordDoc.readParagraphContent();
wordDoc.readTable();
}
}