POI在读写word docx文件时是通过xwpf模块来进行的,其核心是XWPFDocument。
一个XWPFDocument代表一个docx文档,其可以用来读docx文档,也可以用来写docx文档。
XWPFDocument中主要包含下面这几种对象:
- XWPFParagraph:代表一个段落。
- XWPFRun:代表具有相同属性的一段文本。
- XWPFTable:代表一个表格。
- XWPFTableRow:表格的一行。
- XWPFTableCell:表格对应的一个单元格。
1.读docx文件 如果想要读取doc文件需要使用这个HWPFDocument对象,这里就不演示了,话不多说,上代码
1.1首先是依赖
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.17</version>
</dependency>
<!--如果想要操作doc文件还需要导入以下依赖-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-scratchpad</artifactId>
<version>3.17</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>3.17</version>
</dependency>
java 代码,我这里因为特殊需要所以是批量读取的
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 读取文件
*/
public class ReadDir2 {
public static void main(String[] args) throws IOException {
//声明存放学校word文档的文件夹地址
File file = new File("D:\\school");
//去读取
getAllFilePath(file);
}
/**
* 遍历文件夹中的所有文件
* @param dir
* @throws IOException
*/
public static List<Map<String,Object>> getAllFilePath(File dir) throws IOException {
List<Map<String,Object>> list = new ArrayList<>();
Map<String, Object> map = new HashMap<>();
File[] files=dir.listFiles();
for(int i=0;i<files.length;i++){
//判断当前是不是一个文件夹
if(files[i].isDirectory()){
System.out.println(files[i].getPath());
//这里面用了递归的算法 如果是再递归调用自己
getAllFilePath(files[i]);
} else {
String path = files[i].getPath();
String name = files[i].getName();
map = DocxTest2.batchReadWord(path,name);
list.add(map);
//System.out.println("最终的结果");
//System.out.println(map);
}
}
return list;
}
}
import org.apache.poi.xwpf.usermodel.*;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 读取word文档数据
*/
public class DocxTest2 {
//批量读取学校word文档数据
public static Map<String, Object> batchReadWord(String path,String name) throws IOException {
//读取第几个表
Integer num = 0;
InputStream is = new FileInputStream(path);
XWPFDocument doc = new XWPFDocument(is);
List<XWPFParagraph> paras = doc.getParagraphs();
StringBuffer sb = new StringBuffer();
for (XWPFParagraph para : paras) {
/**
我这里是通过专门写了一个读取表格内容的方法
通过匹配到标题名字 就调用下面读取表格内容
*/
//获取表格数据
if (para.getText().equals("国家级(双一流)/部级/重点学科")){
String table = getTable(doc,num);
sb.append("国家级(双一流)/部级/重点学科:<p>"+table);
num++;
//读取完之后 num++ 这样下次再读取就会去找第二个表格的内容
continue;
}
if (para.getText().contains("知名校友")){
//获取表格数据
String table = getTable(doc,num);
sb.append("知名校友:<p>"+table);
continue;
}
//每一段落的数据 para.getText() 这个方法会获取到word文档中每一个段落 获取到拼接起来
//System.out.println(para.getText() + "是一段");
sb.append(para.getText() + "<p>");
}
//程序执行到这里已经把word文档中完整数据全部读取到了
Map<String,Object> map = new HashMap<>();
// map.put("wanZheng",sb);
map.put("name",name);
//下面就去获取单独的数据获取单独数据
Map<String, String> danDu = getDanDu(sb);
//System.out.println(danDu);
map.put("danDu",danDu);
close(is);
return map;
}
/**
* 单独获取其中某一项的值
* @param src
*/
private static Map<String,String> getDanDu(StringBuffer src) {
Map<String,String> map = new HashMap<>();
// 1.获取“院校简介”的位置
Integer descPoi = src.indexOf("院校简介");
// 2.获取学校属地及分校区的位置
Integer shuDiPoi = src.indexOf("学校属地及分校区");
// 3.截取包含院校简介的内容,并保存输出 通过上面两个索引就可以获得中间的段落
//也就是属于简介的段落内容了
String jianJie = src.substring(descPoi + "院校简介".length(), shuDiPoi);
//System.out.println("简介:"+desc);
map.put("jianJie",jianJie);
// 4.获取【学校行政级别】的位置
Integer jiBiePoi = src.indexOf("学校行政级别");
// 5.截取包含学校属地及分区的内容,并保存输出
String shuDi = src.substring(shuDiPoi + "学校属地及分校区".length()+1, jiBiePoi);
//System.out.println("学校属地及分校区:"+shuDi);
map.put("shuDi",shuDi);
//..................下面依此类推,想到获取那部分内容就通过字符串截取的方式去得到他
//然后把数据都封装到map中,最后通过get的方式依次赋值到实体类中
return map;
}
/**
* 获取表格内的数据
* @param doc 文档源
* @param num 第几个表格
* @return
*/
private static String getTable(XWPFDocument doc,Integer num){
//存放最后返回数据
StringBuffer sb = new StringBuffer();
//获取文档中所有的表格
List<XWPFTable> tables = doc.getTables();
//表格中所有的行
List<XWPFTableRow> rows;
//每一行所有的单元格
List<XWPFTableCell> cells;
sb.append("<table>");
//获取到去读取第几个表格
XWPFTable table = tables.get(num);
//获取表格对应的行
rows = table.getRows();
for (XWPFTableRow row : rows) {
//获取行对应的单元格
cells = row.getTableCells();
sb.append("<tr>");
for (XWPFTableCell cell : cells) {
sb.append("<td style='border: 1px solid black;'>" + cell.getText() + "</td>");
}
sb.append("</tr>");
}
sb.append("</table>");
return sb.toString();
}
/**
* 关闭输入流
* @param is
*/
private static void close(InputStream is) {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
总结
大致思路就是 ,首先通过
InputStream is = new FileInputStream(path);
XWPFDocument doc = new XWPFDocument(is);
List<XWPFParagraph> paras = doc.getParagraphs();
这几个方法获取到所有的段落,通过字符串拼接的方式全部拼接起来,
如果中间有表格的格式,就单独抽取一个方法去处理表格内容,也拼接起来
最终得到一个完整内容的字符串,如果需要获取其中某一个段落,或者某几个段落
就通过字符串的一系列索引,截取操作去获取到,最后还是要根据实际的情况去获取的
这样就可以完成一个word文档数据封装到Java实体类的功能了,另外一定要注意,
以上的方法是针对于docx的文档后缀,最后附上读取的文档格式
哦对了对了最后奉上的在做这个功能时觉得还不错的文章
https://www.iteye.com/blog/elim-2049110
https://blog.csdn.net/dongyuancaizi/article/details/78614217