很多时候我们只需要一份文件里的部分信息,当文件量大的时候,一份一份的去找就很费时间了,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文件操作时需要导入的包的解释,所以我直接全部导入。。。(有知道的希望能留一下言,谢谢)——已解决,导包在文章底部

wps pdf插件Java scrip java poi wps_配置文件

wps pdf插件Java scrip java poi wps_wps pdf插件Java scrip_02

四、创建项目结构

wps pdf插件Java scrip java poi wps_配置文件_03

wps pdf插件Java scrip java poi wps_java_04

对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内容相同

wps pdf插件Java scrip java poi wps_wps pdf插件Java scrip_05

wps pdf插件Java scrip java poi wps_wps pdf插件Java scrip_06

配置文件:要求:key与文件名相同,value为要提取数据的正则表达式

wps pdf插件Java scrip java poi wps_配置文件_07

运行结果:

wps pdf插件Java scrip java poi wps_配置文件_08

测试成功!

七、可能遇到的问题

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),需要导入的包为:

wps pdf插件Java scrip java poi wps_Word_09