很多时候我们只需要一份文件里的部分信息,当文件量大的时候,一份一份的去找就很费时间了,java中使用poi可以实现对word、excel、ppt等文件的读取,进而对文件内容进行操作
一、环境
- eclipse(Version: 2019-03 (4.11.0))
- jdk-12.0.1
- poi-4.1.0
二、主要设计
- 配置文件properties
- 反射加载类
- 正则表达式
三、导包
下载POI官方jar包:https://poi.apache.org/ ,由于没找到相关的文档说明,我是解压后直接将所有的jar包复制到项目中
之前jar包没完全导入,在对docx文档读取中使用XWPFWordExtractor extractor = new XWPFWordExtractor(xdoc);时一直显示编译时错误,点击提示只显示build path...百度了看了很多博客只看到有对excel文件操作时需要导入的包的解释,所以我直接全部导入。。。(
有知道的希望能留一下言,谢谢)——已解决,导包在文章底部
四、创建项目结构
对word文件的读取:
- read.office.Word为抽象类,对应的实现类是Doc.java与Docx.java分别读取.doc文件与.docx文件
- read.test.Test类是对最终结果的运行测试
- read.util.Util类是静态方法的集合,包括加载配置文件等
- office.properties配置文件,主要是在提取文件中需要的内容时用到了正则匹配,正则表达式是可变的,所以写在了配置文件中,方便修改
五、源码:
Doc.java
package read.office;
import java.io.File;
import java.io.FileInputStream;
import org.apache.poi.hwpf.extractor.WordExtractor;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
public class Doc extends Word {
public String read(File file) {
try (POIFSFileSystem fileSystem = new POIFSFileSystem(new FileInputStream(file));
WordExtractor extractor = new WordExtractor(fileSystem);) {
return extractor.getText();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
Docx.java
package read.office;
import java.io.File;
import java.io.FileInputStream;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
public class Docx extends Word {
public String read(File file) {
try (XWPFDocument xdoc = new XWPFDocument(new FileInputStream(file));
XWPFWordExtractor extractor = new XWPFWordExtractor(xdoc);) {
return extractor.getText();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
Util.java
package read.util;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Util {
private static Properties properties;
static {//加载配置文件
InputStream url=Util.class.getClassLoader().getResourceAsStream("office.properties");
properties=new Properties();
try {
properties.load(url);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
if(url!=null) {
try {
url.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
//截取目标字符串
public static String subTargetText(String text,String regex) {
Matcher matcher = Pattern.compile(regex).matcher(text);
if(matcher.find()) {
return matcher.group();
}
return null;
}
//根据文件名加载字符串匹配正则
public static String getRegex(String fileName) {
try {//查了资料,因为配置文件默认是按ISO-8859-1进行读取的,所以在如果想按照你想要的格式显示就需要进行转换
String regex=new String(properties.getProperty(fileName).getBytes("ISO-8859-1"),"utf-8");
return regex;
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
配置文件的默认读取是编码ISO-8859-1,哪怕你已经将项目中的所有文件的properties编码属性修改为一致(如utf-8),在进行读取中文的时候还是会出现乱码的情况,所以需要进行转换
Test.java
package read.test;
import java.io.File;
import read.office.Word;
import read.util.Util;
public class Test {
public static void main(String[] args) {
File dir = new File("E:\\大学\\1");
run(dir);
}
// 根据文件的上一级目录的File对象进行文件的遍历
public static void run(File dir) {
File[] files = dir.listFiles();
Word word = null;
for (File file : files) {
try {
String fileName = file.getName();
// 根据文件后缀反射获取对应的类(因为对类的命名是根据文件后缀类型命名的如Doc,Docx)
String temp = fileName.substring(fileName.lastIndexOf(".") + 1);
temp = temp.substring(0, 1).toUpperCase() + temp.substring(1).toLowerCase();
word = (Word) Class.forName("read.office." + temp).getDeclaredConstructor().newInstance();
String text = word.read(file);
System.out.println(text);
// 根据文件名获加载配置文件里的字符匹配正则
temp = fileName.substring(0, fileName.lastIndexOf("."));
System.out.println(fileName);
String result = Util.subTargetText(text, Util.getRegex(temp));
System.out.println(result);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
六、运行测试
读取文件:文件1.与文件2内容相同
配置文件:要求:key与文件名相同,value为要提取数据的正则表达式
运行结果:
测试成功!
七、可能遇到的问题
1、可能我们想要的内容在文档中多处位置都有值,在以上的代码中,只能返回第一个匹配正则表达式的值,而恰好第一个值并不是我们想要的。
原Util.java类中:只能获取第一个值
//截取目标字符串
public static String subTargetText(String text,String regex) {
Matcher matcher = Pattern.compile(regex).matcher(text);
if(matcher.find()) {
return matcher.group();
}
return null;
}
修改后:可获取所有的值,从中选择需要的值
List<String> list=new ArrayList<String>();
//截取目标字符串
public static List<String> subTargetText(String text,String regex) {
Matcher matcher = Pattern.compile(regex).matcher(text);
while(matcher.find()) {
list.add(matcher.group());
}
return list;
}
2、关于导包的问题
poi读取word文件(doc、docx),需要导入的包为: