很多時候我們只需要一份文件裏的部分信息,當文件量大的時候,一份一份的去找就很費時間了,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),需要導入的包爲: