亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

使用POI讀寫Word doc文件

系統(tǒng) 1930 0

使用 POI 讀寫 word doc 文件

目錄

1???? word doc 文件

1.1???? 通過 WordExtractor 讀文件

1.2???? 通過 HWPFDocument 讀文件

2???? word doc 文件

?

?????? Apache poi hwpf 模塊是專門用來對(duì) word doc 文件進(jìn)行讀寫操作的。在 hwpf 里面我們使用 HWPFDocument 來表示一個(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 來獲取的。

?

1.1 ???? 通過 WordExtractor 讀文件

?????? 在使用 WordExtractor 讀文件時(shí)我們只能讀到文件的文本內(nèi)容和基于文檔的一些屬性,至于文檔內(nèi)容的屬性等是無法讀到的。如果要讀到文檔內(nèi)容的屬性則需要使用 HWPFDocument 來讀取了。下面是使用 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());
      //輸出頁眉的內(nèi)容
      System.out.println("頁眉:" + extractor.getHeaderText());
      //輸出頁腳的內(nèi)容
      System.out.println("頁腳:" + 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());
      //頁數(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 中的,也就是說我們改變的是 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 來寫的,而 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少我們的工作量,還可以讓文本的格式更加的清晰。下面我們就來基于這種方式做一個(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)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

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

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

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 一级片亚洲 | 91久久国产视频 | 国产精品亚洲一区二区麻豆 | 综合色99| 天天干天天舔 | 两性视频久久 | 亚洲国产欧美久久香综合 | 欧洲色片 | 欧美肥婆videos另类 | 伊人亚洲 | 九九久久久久午夜精选 | 99视频在线看 | 久久久久久天天夜夜天天 | 亚洲欧美日韩国产 | 欧美日韩一级片在线观看 | 国产亚洲精品久久久久91网站 | 成人精品视频在线观看播放 | 亚洲精品福利在线 | 中文字幕在线观看2023 | 亚洲成精品动漫久久精久 | 国产乱肥老妇精品视频 | 免费一级特黄 欧美大片 | 美女在线国产 | 久久精品亚洲精品一区 | 久久精热 | 色人阁五月| 野外一级毛片 | 狠狠狠色丁香婷婷综合久久五月 | 亚洲欧洲国产精品你懂的 | 亚洲国产女人aaa毛片在线 | 久久激情综合网 | 亚洲精品久久久午夜伊人 | 日日草天天干 | 日本在线视频精品 | 欧美激情精品久久久久久久九九九 | 亚洲精品日韩一区二区 | 四虎家庭影院 | 伊人色综合久久天天网蜜月 | 91福利视频网站 | 一级片在线免费看 | 青青青青爽视频在线播放 |