日韩久久久精品,亚洲精品久久久久久久久久久,亚洲欧美一区二区三区国产精品 ,一区二区福利

使用POI讀寫Word doc文件

系統(tǒng) 1950 0

使用 POI 讀寫 word doc 文件

目錄

1???? word doc 文件

1.1???? 通過 WordExtractor 讀文件

1.2???? 通過 HWPFDocument 讀文件

2???? word doc 文件

?

?????? Apache poi hwpf 模塊是專門用來(lái)對(duì) word doc 文件進(jìn)行讀寫操作的。在 hwpf 里面我們使用 HWPFDocument 來(lái)表示一個(gè) word doc 文檔。在 HWPFDocument 里面有這么幾個(gè)概念:

l ? Range :它表示一個(gè)范圍,這個(gè)范圍可以是整個(gè)文檔,也可以是里面的某一小節(jié)( Section ),也可以是某一個(gè)段落( Paragraph ),還可以是擁有共同屬性的一段文本( CharacterRun )。

l ? Section word 文檔的一個(gè)小節(jié),一個(gè) word 文檔可以由多個(gè)小節(jié)構(gòu)成。

l ? Paragraph word 文檔的一個(gè)段落,一個(gè)小節(jié)可以由多個(gè)段落構(gòu)成。

l ? CharacterRun :具有相同屬性的一段文本,一個(gè)段落可以由多個(gè) CharacterRun 組成。

l ? Table :一個(gè)表格。

l ? TableRow :表格對(duì)應(yīng)的行。

l ? TableCell :表格對(duì)應(yīng)的單元格。

?????? Section 、 Paragraph 、 CharacterRun Table 都繼承自 Range

1 ?????? word doc 文件

?????? 在日常應(yīng)用中,我們從 word 文件里面讀取信息的情況非常少見,更多的還是把內(nèi)容寫入到 word 文件中。使用 POI word doc 文件讀取數(shù)據(jù)時(shí)主要有兩種方式:通過 WordExtractor 讀和通過 HWPFDocument 讀。在 WordExtractor 內(nèi)部進(jìn)行信息讀取時(shí)還是通過 HWPFDocument 來(lái)獲取的。

?

1.1 ???? 通過 WordExtractor 讀文件

?????? 在使用 WordExtractor 讀文件時(shí)我們只能讀到文件的文本內(nèi)容和基于文檔的一些屬性,至于文檔內(nèi)容的屬性等是無(wú)法讀到的。如果要讀到文檔內(nèi)容的屬性則需要使用 HWPFDocument 來(lái)讀取了。下面是使用 WordExtractor 讀取文件的一個(gè)示例:

      public class HwpfTest {
 
   @SuppressWarnings("deprecation")
   @Test
   public void testReadByExtractor() throws Exception {
      InputStream is = new FileInputStream("D:\\test.doc");
      WordExtractor extractor = new WordExtractor(is);
      //輸出word文檔所有的文本
      System.out.println(extractor.getText());
      System.out.println(extractor.getTextFromPieces());
      //輸出頁(yè)眉的內(nèi)容
      System.out.println("頁(yè)眉:" + extractor.getHeaderText());
      //輸出頁(yè)腳的內(nèi)容
      System.out.println("頁(yè)腳:" + extractor.getFooterText());
      //輸出當(dāng)前word文檔的元數(shù)據(jù)信息,包括作者、文檔的修改時(shí)間等。
      System.out.println(extractor.getMetadataTextExtractor().getText());
      //獲取各個(gè)段落的文本
      String paraTexts[] = extractor.getParagraphText();
      for (int i=0; i<paraTexts.length; i++) {
         System.out.println("Paragraph " + (i+1) + " : " + paraTexts[i]);
      }
      //輸出當(dāng)前word的一些信息
      printInfo(extractor.getSummaryInformation());
      //輸出當(dāng)前word的一些信息
      this.printInfo(extractor.getDocSummaryInformation());
      this.closeStream(is);
   }
  
   /**
    * 輸出SummaryInfomation
    * @param info
    */
   private void printInfo(SummaryInformation info) {
      //作者
      System.out.println(info.getAuthor());
      //字符統(tǒng)計(jì)
      System.out.println(info.getCharCount());
      //頁(yè)數(shù)
      System.out.println(info.getPageCount());
      //標(biāo)題
      System.out.println(info.getTitle());
      //主題
      System.out.println(info.getSubject());
   }
  
   /**
    * 輸出DocumentSummaryInfomation
    * @param info
    */
   private void printInfo(DocumentSummaryInformation info) {
      //分類
      System.out.println(info.getCategory());
      //公司
      System.out.println(info.getCompany());
   }
  
   /**
    * 關(guān)閉輸入流
    * @param is
    */
   private void closeStream(InputStream is) {
      if (is != null) {
         try {
            is.close();
         } catch (IOException e) {
            e.printStackTrace();
         }
      }
   }
  
}
    

?

?

1.2 ???? 通過 HWPFDocument 讀文件

?????? HWPFDocument 是當(dāng)前 Word 文檔的代表,它的功能比 WordExtractor 要強(qiáng)。通過它我們可以讀取文檔中的表格、列表等,還可以對(duì)文檔的內(nèi)容進(jìn)行新增、修改和刪除操作。只是在進(jìn)行完這些新增、修改和刪除后相關(guān)信息是保存在 HWPFDocument 中的,也就是說(shuō)我們改變的是 HWPFDocument ,而不是磁盤上的文件。如果要使這些修改生效的話,我們可以調(diào)用 HWPFDocument write 方法把修改后的 HWPFDocument 輸出到指定的輸出流中。這可以是原文件的輸出流,也可以是新文件的輸出流(相當(dāng)于另存為)或其它輸出流。下面是一個(gè)通過 HWPFDocument 讀文件的示例:

      public class HwpfTest {
  
   @Test
   public void testReadByDoc() throws Exception {
      InputStream is = new FileInputStream("D:\\test.doc");
      HWPFDocument doc = new HWPFDocument(is);
      //輸出書簽信息
      this.printInfo(doc.getBookmarks());
      //輸出文本
      System.out.println(doc.getDocumentText());
      Range range = doc.getRange();
//    this.insertInfo(range);
      this.printInfo(range);
      //讀表格
      this.readTable(range);
      //讀列表
      this.readList(range);
      //刪除range
      Range r = new Range(2, 5, doc);
      r.delete();//在內(nèi)存中進(jìn)行刪除,如果需要保存到文件中需要再把它寫回文件
      //把當(dāng)前HWPFDocument寫到輸出流中
      doc.write(new FileOutputStream("D:\\test.doc"));
      this.closeStream(is);
   }
  
   /**
    * 關(guān)閉輸入流
    * @param is
    */
   private void closeStream(InputStream is) {
      if (is != null) {
         try {
            is.close();
         } catch (IOException e) {
            e.printStackTrace();
         }
      }
   }
  
   /**
    * 輸出書簽信息
    * @param bookmarks
    */
   private void printInfo(Bookmarks bookmarks) {
      int count = bookmarks.getBookmarksCount();
      System.out.println("書簽數(shù)量:" + count);
      Bookmark bookmark;
      for (int i=0; i<count; i++) {
         bookmark = bookmarks.getBookmark(i);
         System.out.println("書簽" + (i+1) + "的名稱是:" + bookmark.getName());
         System.out.println("開始位置:" + bookmark.getStart());
         System.out.println("結(jié)束位置:" + bookmark.getEnd());
      }
   }
  
   /**
    * 讀表格
    * 每一個(gè)回車符代表一個(gè)段落,所以對(duì)于表格而言,每一個(gè)單元格至少包含一個(gè)段落,每行結(jié)束都是一個(gè)段落。
    * @param range
    */
   private void readTable(Range range) {
      //遍歷range范圍內(nèi)的table。
      TableIterator tableIter = new TableIterator(range);
      Table table;
      TableRow row;
      TableCell cell;
      while (tableIter.hasNext()) {
         table = tableIter.next();
         int rowNum = table.numRows();
         for (int j=0; j<rowNum; j++) {
            row = table.getRow(j);
            int cellNum = row.numCells();
            for (int k=0; k<cellNum; k++) {
                cell = row.getCell(k);
                //輸出單元格的文本
                System.out.println(cell.text().trim());
            }
         }
      }
   }
  
   /**
    * 讀列表
    * @param range
    */
   private void readList(Range range) {
      int num = range.numParagraphs();
      Paragraph para;
      for (int i=0; i<num; i++) {
         para = range.getParagraph(i);
         if (para.isInList()) {
            System.out.println("list: " + para.text());
         }
      }
   }
  
   /**
    * 輸出Range
    * @param range
    */
   private void printInfo(Range range) {
      //獲取段落數(shù)
      int paraNum = range.numParagraphs();
      System.out.println(paraNum);
      for (int i=0; i<paraNum; i++) {
//       this.insertInfo(range.getParagraph(i));
         System.out.println("段落" + (i+1) + ":" + range.getParagraph(i).text());
         if (i == (paraNum-1)) {
            this.insertInfo(range.getParagraph(i));
         }
      }
      int secNum = range.numSections();
      System.out.println(secNum);
      Section section;
      for (int i=0; i<secNum; i++) {
         section = range.getSection(i);
         System.out.println(section.getMarginLeft());
         System.out.println(section.getMarginRight());
         System.out.println(section.getMarginTop());
         System.out.println(section.getMarginBottom());
         System.out.println(section.getPageHeight());
         System.out.println(section.text());
      }
   }
  
   /**
    * 插入內(nèi)容到Range,這里只會(huì)寫到內(nèi)存中
    * @param range
    */
   private void insertInfo(Range range) {
      range.insertAfter("Hello");
   }
  
}
    

?

?

2 ?????? word doc 文件

?????? 在使用 POI word doc 文件的時(shí)候我們必須要先有一個(gè) doc 文件才行,因?yàn)槲覀冊(cè)趯? doc 文件的時(shí)候是通過 HWPFDocument 來(lái)寫的,而 HWPFDocument 是要依附于一個(gè) doc 文件的。所以通常的做法是我們先在硬盤上準(zhǔn)備好一個(gè)內(nèi)容空白的 doc 文件,然后建立一個(gè)基于該空白文件的 HWPFDocument 。之后我們就可以往 HWPFDocument 里面新增內(nèi)容了,然后再把它寫入到另外一個(gè) doc 文件中,這樣就相當(dāng)于我們使用 POI 生成了 word doc 文件。

?????? 在實(shí)際應(yīng)用中,我們?cè)谏? word 文件的時(shí)候都是生成某一類文件,該類文件的格式是固定的,只是某些字段不一樣罷了。所以在實(shí)際應(yīng)用中,我們大可不必將整個(gè) word 文件的內(nèi)容都通過 HWPFDocument 生成。而是先在磁盤上新建一個(gè) word 文檔,其內(nèi)容就是我們需要生成的 word 文件的內(nèi)容,然后把里面一些屬于變量的內(nèi)容使用類似于“ ${paramName} ”這樣的方式代替。這樣我們?cè)诨谀承┬畔⑸? word 文件的時(shí)候,只需要獲取基于該 word 文件的 HWPFDocument ,然后調(diào)用 Range replaceText() 方法把對(duì)應(yīng)的變量替換為對(duì)應(yīng)的值即可,之后再把當(dāng)前的 HWPFDocument 寫入到新的輸出流中。這種方式在實(shí)際應(yīng)用中用的比較多,因?yàn)樗坏梢詼p少我們的工作量,還可以讓文本的格式更加的清晰。下面我們就來(lái)基于這種方式做一個(gè)示例。

?????? 假設(shè)我們現(xiàn)在擁有一些變動(dòng)的信息,然后需要通過這些信息生成如下格式的 word doc 文件:


使用POI讀寫Word doc文件
?

?????? 那么根據(jù)上面的描述,首先第一步,我們建立一個(gè)對(duì)應(yīng)格式的 doc 文件作為模板,其內(nèi)容是這樣的:


使用POI讀寫Word doc文件
?

?????? 有了這樣一個(gè)模板之后,我們就可以建立對(duì)應(yīng)的 HWPFDocument ,然后替換對(duì)應(yīng)的變量為相應(yīng)的值,再把 HWPFDocument 輸出到對(duì)應(yīng)的輸出流即可。下面是對(duì)應(yīng)的代碼。

      public class HwpfTest {
  
   @Test
   public void testWrite() throws Exception {
      String templatePath = "D:\\word\\template.doc";
      InputStream is = new FileInputStream(templatePath);
      HWPFDocument doc = new HWPFDocument(is);
      Range range = doc.getRange();
      //把range范圍內(nèi)的${reportDate}替換為當(dāng)前的日期
      range.replaceText("${reportDate}", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
      range.replaceText("${appleAmt}", "100.00");
      range.replaceText("${bananaAmt}", "200.00");
      range.replaceText("${totalAmt}", "300.00");
      OutputStream os = new FileOutputStream("D:\\word\\write.doc");
      //把doc輸出到輸出流中
      doc.write(os);
      this.closeStream(os);
      this.closeStream(is);
   }
  
   /**
    * 關(guān)閉輸入流
    * @param is
    */
   private void closeStream(InputStream is) {
      if (is != null) {
         try {
            is.close();
         } catch (IOException e) {
            e.printStackTrace();
         }
      }
   }
 
   /**
    * 關(guān)閉輸出流
    * @param os
    */
   private void closeStream(OutputStream os) {
      if (os != null) {
         try {
            os.close();
         } catch (IOException e) {
            e.printStackTrace();
         }
      }
   }
  
 
}
    

?

(注:本文是基于 poi3.9 所寫)

使用POI讀寫Word doc文件


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長(zhǎng)會(huì)非常 感謝您的哦?。?!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 洛川县| 元氏县| 高安市| 富源县| 普兰县| 嘉定区| 青龙| 荃湾区| 潼关县| 石阡县| 大关县| 郯城县| 庆安县| 融水| 莱州市| 新和县| 麟游县| 深圳市| 开化县| 融水| 平湖市| 新津县| 四平市| 光山县| 雷山县| 勃利县| 新沂市| 郑州市| 仁怀市| 历史| 武邑县| 壶关县| 樟树市| 吴桥县| 襄汾县| 磐石市| 青龙| 宁明县| 东乌珠穆沁旗| 咸阳市| 平原县|