用java語言通過POI實現word文檔的按標題提取


最近有一個項目需要將一個word文檔中的數據提取到數據庫中。就去網上查了好多資料,最靠譜的就是用poi實現word文檔的提取。

喝水不忘挖井人,我查了好多資料就這個最靠譜,我的這篇博客主要是借鑒https://blog.csdn.net/qq_16601953/article/details/82415518

 

現在講一下思路:

1.首先我們要用poi將word中的數據提取出來,我把提取的數據存到字符數組中,

2.然后通過sql數據將字符串數組中的數據存到mysql數據庫中

當然需要jar包依賴

可能不需要這么多,但是我都導進去了

網上有poi的下載鏈接http://120.52.51.14/archive.apache.org/dist/poi/release/bin/poi-bin-3.17-20170915.zip

如果實在找不到的話加我 

下面貼上主要代碼我是按照上面博客借鑒的稍微根據我的需求改了改

  1 import java.io.FileInputStream;
  2 import java.io.FileOutputStream;
  3 import java.io.IOException;
  4 import java.io.InputStream;
  5 import java.io.OutputStream;
  6 import java.math.BigInteger;
  7 import java.util.HashMap;
  8 import java.util.List;
  9 import java.util.Map;
 10 
 11 import org.apache.poi.xwpf.usermodel.XWPFDocument;
 12 import org.apache.poi.xwpf.usermodel.XWPFParagraph;
 13 import org.apache.poi.xwpf.usermodel.XWPFRun;
 14 import org.apache.poi.xwpf.usermodel.XWPFStyle;
 15 import org.apache.poi.xwpf.usermodel.XWPFStyles;
 16 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDecimalNumber;
 17 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTOnOff;
 18 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr;
 19 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTString;
 20 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyle;
 21 import org.openxmlformats.schemas.wordprocessingml.x2006.main.STStyleType;
 22 
 23 
 24 public class test {
 25 private static Map<String,Map<String,Object>> orderMap =new HashMap<String, Map<String,Object>>();
 26 
 27     public void init(String targetPath,String sourcePath){
 28         InputStream is = null;
 29         XWPFDocument doc=null;
 30         OutputStream out=null;
 31         try {
 32             XWPFDocument createDoc = new XWPFDocument();
 33 
 34             is = new FileInputStream(sourcePath);
 35             doc = new XWPFDocument(is);
 36             //獲取段落
 37             List<XWPFParagraph> paras=doc.getParagraphs();
 38 
 39             for (XWPFParagraph para : paras){
 40  //             System.out.println(para.getCTP());//得到xml格式
 41               System.out.println(para.getStyleID());//段落級別
 42               System.out.println(para.getParagraphText());//段落內容
 43 
 44                 String titleLvl = getTitleLvl(doc,para);//獲取段落級別
 45                 if("a5".equals(titleLvl)||"HTML".equals(titleLvl)||"".equals(titleLvl)||null==titleLvl){
 46                     titleLvl = "8";
 47                 }
 48               System.out.println(titleLvl+"-----");//0,1,2
 49                 if(!"8".equals(titleLvl)){
 50                     System.out.println(titleLvl+"===="+para.getParagraphText());
 51                 }
 52 
 53 
 54                 XWPFParagraph ctPara = createDoc.createParagraph();
 55                 //一個XWPFRun代表具有相同屬性的一個區域。
 56                 XWPFRun ctRun = ctPara.createRun();
 57                 String ctText = para.getParagraphText();
 58                 ctRun.setFontFamily("宋體");//字體
 59                 ctRun.setFontSize(12);
 60 
 61                 if(null!=titleLvl&&!"".equals(titleLvl)&&!"8".equals(titleLvl)){
 62                     addCustomHeadingStyle(createDoc,titleLvl,Integer.parseInt(titleLvl));
 63                     String orderCode = getOrderCode(titleLvl);//獲取編號
 64                     ctText = orderCode+" "+ctText;
 65                     ctRun.setBold(true);//標題加粗
 66                     ctRun.setFontSize(14);
 67 
 68                     ctPara.setStyle(titleLvl);
 69 
 70                 }else{//正文
 71                     ctPara.setIndentationFirstLine(567);//首行縮進:567==1厘米
 72 //                  ctRun.setTextPosition(6);//設置行間距
 73                 }
 74 
 75                 ctRun.setText(ctText);//內容
 76             }
 77             out=new FileOutputStream(targetPath);
 78             createDoc.write(out);
 79         } catch (Exception e) {
 80             e.printStackTrace();
 81         } finally{
 82             try {
 83                 if(null!=out){
 84                     out.close();
 85                 } 
 86                 if(null!=is){
 87                     is.close();
 88                 }
 89             }catch (IOException e) {
 90                 e.printStackTrace();
 91             }
 92         }
 93     }
 94 
 95     /**
 96      * Word中的大綱級別,可以通過getPPr().getOutlineLvl()直接提取,但需要注意,Word中段落級別,通過如下三種方式定義: 
 97      *  1、直接對段落進行定義; 
 98      *  2、對段落的樣式進行定義; 
 99      *  3、對段落樣式的基礎樣式進行定義。 
100      *  因此,在通過“getPPr().getOutlineLvl()”提取時,需要依次在如上三處讀取。
101      * @param doc
102      * @param para
103      * @return
104      */
105     private static String getTitleLvl(XWPFDocument doc, XWPFParagraph para) {
106         String titleLvl = "";
107         try {
108             //判斷該段落是否設置了大綱級別
109             if (para.getCTP().getPPr().getOutlineLvl() != null) {
110                 // System.out.println("getCTP()");
111 //              System.out.println(para.getParagraphText());
112 //              System.out.println(para.getCTP().getPPr().getOutlineLvl().getVal());
113 
114                 return String.valueOf(para.getCTP().getPPr().getOutlineLvl().getVal());
115             }
116         } catch (Exception e) {
117 
118         }
119 
120         try {
121             //判斷該段落的樣式是否設置了大綱級別
122             if (doc.getStyles().getStyle(para.getStyle()).getCTStyle().getPPr().getOutlineLvl() != null) {
123 
124                 // System.out.println("getStyle");
125 //              System.out.println(para.getParagraphText());
126 //              System.out.println(doc.getStyles().getStyle(para.getStyle()).getCTStyle().getPPr().getOutlineLvl().getVal());
127 
128                 return String.valueOf(doc.getStyles().getStyle(para.getStyle()).getCTStyle().getPPr().getOutlineLvl().getVal());
129             }
130         } catch (Exception e) {
131 
132         }
133 
134         try {
135             //判斷該段落的樣式的基礎樣式是否設置了大綱級別
136             if (doc.getStyles().getStyle(doc.getStyles().getStyle(para.getStyle()).getCTStyle().getBasedOn().getVal())
137                     .getCTStyle().getPPr().getOutlineLvl() != null) {
138                 // System.out.println("getBasedOn");
139 //              System.out.println(para.getParagraphText());
140                 String styleName = doc.getStyles().getStyle(para.getStyle()).getCTStyle().getBasedOn().getVal();
141 //              System.out.println(doc.getStyles().getStyle(styleName).getCTStyle().getPPr().getOutlineLvl().getVal());
142 
143                 return String.valueOf(doc.getStyles().getStyle(styleName).getCTStyle().getPPr().getOutlineLvl().getVal());
144             }
145         } catch (Exception e) {
146 
147         }
148 
149         try {
150             if(para.getStyleID()!=null){
151                 return para.getStyleID();
152             }
153         } catch (Exception e) {
154 
155         }
156 
157         return titleLvl;
158     }
159 
160     /**
161      * 增加自定義標題樣式。這里用的是stackoverflow的源碼
162      * 
163      * @param docxDocument 目標文檔
164      * @param strStyleId 樣式名稱
165      * @param headingLevel 樣式級別
166      */
167     private static void addCustomHeadingStyle(XWPFDocument docxDocument, String strStyleId, int headingLevel) {
168 
169         strStyleId = String.valueOf(Integer.parseInt(strStyleId)+1);
170         CTStyle ctStyle = CTStyle.Factory.newInstance();
171         ctStyle.setStyleId(strStyleId);
172 
173         CTString styleName = CTString.Factory.newInstance();
174         styleName.setVal(strStyleId);
175         ctStyle.setName(styleName);
176 
177         CTDecimalNumber indentNumber = CTDecimalNumber.Factory.newInstance();
178         indentNumber.setVal(BigInteger.valueOf(headingLevel));
179 
180         // lower number > style is more prominent in the formats bar
181         ctStyle.setUiPriority(indentNumber);
182 
183         CTOnOff onoffnull = CTOnOff.Factory.newInstance();
184         ctStyle.setUnhideWhenUsed(onoffnull);
185 
186         // style shows up in the formats bar
187         ctStyle.setQFormat(onoffnull);
188 
189         // style defines a heading of the given level
190         CTPPr ppr = CTPPr.Factory.newInstance();
191         ppr.setOutlineLvl(indentNumber);
192         ctStyle.setPPr(ppr);
193 
194         XWPFStyle style = new XWPFStyle(ctStyle);
195 
196         // is a null op if already defined
197         XWPFStyles styles = docxDocument.createStyles();
198 
199         style.setType(STStyleType.PARAGRAPH);
200         styles.addStyle(style);
201 
202     }
203     /**
204      * 獲取標題編號
205      * @param titleLvl
206      * @return
207      */
208     private static String getOrderCode(String titleLvl) {
209         String order = "";
210 
211         if("0".equals(titleLvl)||Integer.parseInt(titleLvl)==8){//文檔標題||正文
212             return "";
213         }else if(Integer.parseInt(titleLvl)>0&&Integer.parseInt(titleLvl)<8){//段落標題
214 
215             //設置最高級別標題
216             Map<String,Object> maxTitleMap = orderMap.get("maxTitleLvlMap");
217             if(null==maxTitleMap){//沒有,表示第一次進來
218                 //最高級別標題賦值
219                 maxTitleMap = new HashMap<String, Object>();
220                 maxTitleMap.put("lvl", titleLvl);
221                 orderMap.put("maxTitleLvlMap", maxTitleMap);
222             }else{
223                 String maxTitleLvl = maxTitleMap.get("lvl")+"";//最上層標題級別(0,1,2,3)
224                 if(Integer.parseInt(titleLvl)<Integer.parseInt(maxTitleLvl)){//當前標題級別更高
225                     maxTitleMap.put("lvl", titleLvl);//設置最高級別標題
226                     orderMap.put("maxTitleLvlMap", maxTitleMap);
227                 }
228             }
229 
230             //查父節點標題
231             int parentTitleLvl = Integer.parseInt(titleLvl)-1;//父節點標題級別
232             Map<String,Object> cMap = orderMap.get(titleLvl);//當前節點信息
233             Map<String,Object> pMap = orderMap.get(parentTitleLvl+"");//父節點信息
234 
235             if(0==parentTitleLvl){//父節點為文檔標題,表明當前節點為1級標題
236                 int count= 0;
237                 //最上層標題,沒有父節點信息
238                 if(null==cMap){//沒有當前節點信息
239                     cMap = new HashMap<String, Object>();
240                 }else{
241                     count = Integer.parseInt(String.valueOf(cMap.get("cCount")));//當前序個數
242                 }
243                 count++;
244                 order = count+"";
245                 cMap.put("cOrder", order);//當前序
246                 cMap.put("cCount", count);//當前序個數
247                 orderMap.put(titleLvl, cMap);
248 
249             }else{//父節點為非文檔標題
250                 int count= 0;
251                 //如果沒有相鄰的父節點信息,當前標題級別自動升級
252                 if(null==pMap){
253                     return getOrderCode(String.valueOf(parentTitleLvl));
254                 }else{
255                     String pOrder = String.valueOf(pMap.get("cOrder"));//父節點序
256                     if(null==cMap){//沒有當前節點信息
257                         cMap = new HashMap<String, Object>();
258                     }else{
259                         count = Integer.parseInt(String.valueOf(cMap.get("cCount")));//當前序個數
260                     }
261                     count++;
262                     order = pOrder+"."+count;//當前序編號
263                     cMap.put("cOrder", order);//當前序
264                     cMap.put("cCount", count);//當前序個數
265                     orderMap.put(titleLvl, cMap);
266                 }
267             }
268 
269             //字節點標題計數清零
270             int childTitleLvl = Integer.parseInt(titleLvl)+1;//子節點標題級別
271             Map<String,Object> cdMap = orderMap.get(childTitleLvl+"");//
272             if(null!=cdMap){
273                 cdMap.put("cCount", 0);//子節點序個數
274                 orderMap.get(childTitleLvl+"").put("cCount", 0);
275             }
276         }
277         return order;
278     }
279 
280     public static void main(String[] args) {
281         InputStream is = null;
282         XWPFDocument doc=null;
283         OutputStream out=null;
284         String[] title= new String [276];
285         String[] concent= new String [276];
286         String[] type= new String [276];
287         int i=0;
288         try {
289             XWPFDocument createDoc = new XWPFDocument();
290 
291             is = new FileInputStream("E:/doc/a.docx");
292             doc = new XWPFDocument(is);
293             //獲取段落
294             List<XWPFParagraph> paras=doc.getParagraphs();
295 
296             for (XWPFParagraph para : paras){
297               //System.out.println(para.getCTP());//得到xml格式
298               //System.out.println(para.getStyleID());//段落級別
299              // System.out.println(para.getParagraphText());//段落內容
300               String titleLvl = getTitleLvl(doc,para);//獲取段落級別
301               if("a5".equals(titleLvl)||"HTML".equals(titleLvl)||"".equals(titleLvl)||null==titleLvl){
302                   titleLvl = "8";
303               }
304             //System.out.println(titleLvl+"-----");//0,1,2
305              if(!"8".equals(titleLvl)){
306                 //System.out.println(titleLvl+"===="+para.getParagraphText());
307                 
308                 if("3".equals(titleLvl)) {
309                     
310                     if(concent[i]!=null)
311                     concent[i]=concent[i]+para.getParagraphText();
312                     else
313                     concent[i]=para.getParagraphText();
314                     //System.out.println(concent[i]);
315                 }
316                 if("2".equals(titleLvl)) {
317                     i++;
318                     title[i]=para.getParagraphText();
319                     type[i]=type[i-1];
320                     //System.out.println(title[i]);
321                 }
322                 if("1".equals(titleLvl)) {
323                     i++;
324                     type[i]=para.getParagraphText();     
325                     //System.out.println(title[i]);
326                 }
327             }
328             
329 
330             }
331             for(int j=2;j<title.length;j++) {
332                 if(title[j]!=null) {
333                     String sql = "INSERT INTO shuju (title,concent,type)VALUES ('"+title[j]+"','"+concent[j]+"','"+type[j]+"')";
334                     DBUtil jdbc=new DBUtil();
335                     int result=jdbc.executeUpdate(sql);
336                     jdbc.close();
337                     //System.out.println(type[j]);
338                 //System.out.println(title[j]);
339                 //System.out.println(concent[j]);
340                 }
341             }
342         } catch (Exception e) {
343             e.printStackTrace();
344         } finally{
345             try {
346                 if(null!=out){
347                     out.close();
348                 } 
349                 if(null!=is){
350                     is.close();
351                 }
352             }catch (IOException e) {
353                 e.printStackTrace();
354             }
355         }
356     }
357 }

ps:331到341是導入到數據庫的需要新建數據庫工具類

你自己弄就OK

如果是單純的讀取的話用下面的代碼,因為上面比較繁瑣我都不太理解,下面的代碼比較簡單易懂,當然功能相對也少,只能讀取所有內容不能識別標題

借鑒的哪一篇博客因為時間太長了,我忘了,抱歉

  1 package com.poi.test;
  2  
  3 import java.io.File;
  4 import java.io.FileInputStream;
  5 import java.io.InputStream;
  6  
  7 import org.apache.poi.POIXMLDocument;
  8 import org.apache.poi.POIXMLTextExtractor;
  9 import org.apache.poi.hwpf.extractor.WordExtractor;
 10 import org.apache.poi.openxml4j.opc.OPCPackage;
 11 import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
 12  
 13 public class testPoi {
 14     /**
 15      * 讀取word文件內容
 16      * 
 17      * @param path
 18      * @return buffer
 19      */
 20  
 21     public String readWord(String path) {
 22         String buffer = "";
 23         try {
 24             if (path.endsWith(".doc")) {
 25                 InputStream is = new FileInputStream(new File(path));
 26                 WordExtractor ex = new WordExtractor(is);
 27                 buffer = ex.getText();
 28                 ex.close();
 29             } else if (path.endsWith("docx")) {
 30                 OPCPackage opcPackage = POIXMLDocument.openPackage(path);
 31                 POIXMLTextExtractor extractor = new XWPFWordExtractor(opcPackage);
 32                 buffer = extractor.getText();
 33                 extractor.close();
 34             } else {
 35                 System.out.println("此文件不是word文件!");
 36             }
 37  
 38         } catch (Exception e) {
 39             e.printStackTrace();
 40         }
 41  
 42         return buffer;
 43     }
 44  
 45     public static void main(String[] args) {
 46         // TODO Auto-generated method stub
 47         testPoi tp = new testPoi();
 48         String content = tp.readWord("自己的路徑.doc");
 49         //String arr[]=content.split("\\d+");
 50         //String arr[]=content.split("第"+"\\w"+"章");
 51         String arr[]=content.split("\\r\\n");
 52         /*String[] a=arr[13].split("\\d+");
 53         String[] b=a[1].split("\\s+");
 54         System.out.println(b[1]);*/
 55         String[] reci = new String [276];;
 56         for(int i=12,j=0;i<290;i++,j++) {
 57             arr[i]=arr[i]+"1";
 58             if(!arr[i].equals("1")) {
 59             
 60             if(i<27) {//判斷頁面數是否為單數
 61                 String[] a=arr[i].split("\\d+|\\s+");
 62             if(arr[i]!="\\s+") {//判斷該元素是否為連續空格
 63                 if(a.length==2) {//判斷該元素是否為標題即分割成2個段
 64                     reci[j]=a[1];
 65                 System.out.println(a[1]);
 66                 }
 67                 else if(a.length==1) {
 68                     reci[j]=a[1];
 69                 System.out.println(arr[i]);
 70                 }
 71                 else//否則該元素是平常元素可以分割成3個段
 72                     {
 73                     reci[j]=a[2];
 74                     System.out.println(a[2]);
 75                     }
 76                 }
 77         }
 78             else {
 79                 String[] a=arr[i].split("\\d{2,3}|\\s+|\\t");
 80                     if(arr[i]!="\\s+") {//判斷該元素是否為連續空格
 81                         if(a.length==2) {
 82                             reci[j]=a[1];
 83                             System.out.println(a[1]);
 84                         }
 85                         else if(a.length==1) {
 86                             reci[j]=a[1];
 87                             System.out.println(arr[i]+i);
 88                         }
 89                         else if(a.length==4) {
 90                             reci[j]=a[1];
 91                             System.out.println(a[1]);
 92                         }
 93                         else
 94                             {reci[j]=a[2];
 95                             System.out.println(a[2]);
 96                             }
 97                     }
 98             }
 99         }
100     }
101         String fengefu=reci[0];
102         for(int i=1;i<276;i++) {
103             if(reci[i]!=null)
104         fengefu=fengefu+"|"+reci[i];
105 
106         }
107         System.out.println(reci[275]);
108         System.out.println(fengefu);
109         String arr2[]=content.split(fengefu);
110         for(int i=0;i<200;i++)
111             System.out.println(arr2[i]);
112     }
113 }

還有下面這一種方法,與上面相似

 1 package com.xxx.util;
 2  
 3 import java.io.File;
 4 import java.io.FileInputStream;
 5 import java.io.IOException;
 6  
 7 import org.apache.poi.hwpf.extractor.WordExtractor;
 8  
 9 public class DocUtil {
10     /**
11      * 讀取doc文件內容
12      * 
13      * @param file
14      *            想要讀取的文件對象
15      * @return 返回文件內容
16      * @throws IOException
17      */
18     public static String doc2String(FileInputStream fs) throws IOException {
19         StringBuilder result = new StringBuilder();
20         WordExtractor re = new WordExtractor(fs);
21         result.append(re.getText());
22         re.close();
23         return result.toString();
24     }
25  
26     public static String doc2String(File file) throws IOException {
27         return doc2String(new FileInputStream(file));
28     }
29  
30     public static void main(String[] args) {
31         File file = new File("自己的路徑.doc");
32         try {
33             System.out.println(doc2String(file));
34         } catch (IOException e) {
35             e.printStackTrace();
36         }
37     }
38 }

結果截圖因為一部分原因就不貼出來了

當然對於poi我還是比較陌生,希望大牛們批評指正


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM