JAVA筆記-如何將百萬級數據高效的導出到Excel表單


 今天,一朋友問我使用JAVA有沒有什麼辦法導出百萬級的數據到Excel工作表。

  當時我的第一個念頭就是這真的是一個好瘋狂的念頭。然後就想假如真的有這樣類似的需求,我自己應該怎麼做呢?

  

  ps: 首先科普一下基礎知識

  Excel 2003及以下的版本。一張表最大支持65536數據,256列。也就是說excel2003完全不可能滿足百萬數據導出的需求。

  Excel 2007-2010版本。一張表最大支持1048576行,16384列;

  筆者使用的是office 2010,更高的版本筆者沒有使用過,暫時無法判斷。

  由此看來百萬級的數據量對Excel自身已經是屬於接近極限的程度。

  假如我們有更大的需求怎麼辦呢?

  既然單表支持最大是104w條數據,那麼更大的需求量我們就只能通過程序級分表操作的方式來實現了。O(∩_∩)O哈哈~

 

  對於操作Excel的類庫。筆者其實瞭解的並不是很多。只是很早以前使用過POI這個類庫,感覺很不錯。於是決定從它入手。看看POI有沒有什麼比較有效的好點的解決辦法。由於筆者以前使用的POI版本比較低。而且使用於excel 2003版本。所以遇到了不少問題。

  

  編輯器: Intellij IDEA 13.2

  類庫需求: POI-3.10-Final

1 <dependency>
2             <groupId>org.apache.poi</groupId>
3             <artifactId>poi</artifactId>
4             <version>3.10-FINAL</version>
5         </dependency>

 

  新建一個Maven項目。

  根據筆者以往的經驗,直接使用POI寫了一份代碼。執行的時候直接報錯了。

複製代碼
 1 public static void Excel2003Operate(String filePath) throws Exception {
 2         HSSFWorkbook hssfWorkbook = new HSSFWorkbook(new FileInputStream(new File(filePath)));
 3         HSSFSheet sheet = hssfWorkbook.getSheetAt(0);
 4         for (int i = 0; i < 10000; i++) {
 5             HSSFRow hssfRow = sheet.createRow(i);
 6             for (int j = 0; j < 10; j++) {
 7                 HSSFCellUtil.createCell(hssfRow, j, String.valueOf(Math.random()));
 8             }
 9         }
10         FileOutputStream out = new FileOutputStream("workbook.xlsx");
11         hssfWorkbook.write(out);
12         out.close();
13     }
複製代碼
複製代碼
 1 Connected to the target VM, address: '127.0.0.1:62382', transport: 'socket'
 2 Exception in thread "main" org.apache.poi.poifs.filesystem.OfficeXmlFileException: The supplied data appears to be in the Office 2007+ XML. You are calling the part of POI that deals with OLE2 Office Documents. You need to call a different part of POI to process this data (eg XSSF instead of HSSF)
 3     at org.apache.poi.poifs.storage.HeaderBlock.<init>(HeaderBlock.java:131)
 4     at org.apache.poi.poifs.storage.HeaderBlock.<init>(HeaderBlock.java:104)
 5     at org.apache.poi.poifs.filesystem.POIFSFileSystem.<init>(POIFSFileSystem.java:128)
 6     at org.apache.poi.hssf.usermodel.HSSFWorkbook.<init>(HSSFWorkbook.java:342)
 7     at org.apache.poi.hssf.usermodel.HSSFWorkbook.<init>(HSSFWorkbook.java:323)
 8     at dev.tinyz.excel.POIUtil.Excel2003Operate(POIUtil.java:23)
 9     at dev.tinyz.excel.Main.main(Main.java:16)
10 Disconnected from the target VM, address: '127.0.0.1:62382', transport: 'socket'
複製代碼

  運行直接報錯了。仔細看了報錯信息之後發現。POI要操作excel 2007及以上的版本需要使用XSSF來代替上面代碼的HSSF。

  

  發現類庫居然沒有XSSF相關的類。着筆者傻眼了說。於是去POI官網查看。發現完整的POI類庫包含的內容很多。於是詳細瞭解了一下每個部分的具體作用:

  poi-ooxml和poi-ooxml-schemas是poi對2007及以上版本的擴充。於是在maven依賴中增加:

複製代碼
 1 <dependency>
 2             <groupId>org.apache.poi</groupId>
 3             <artifactId>poi-ooxml</artifactId>
 4             <version>3.10-FINAL</version>
 5         </dependency>
 6         <dependency>
 7             <groupId>org.apache.poi</groupId>
 8             <artifactId>poi-ooxml-schemas</artifactId>
 9             <version>3.10-FINAL</version>
10         </dependency>
複製代碼

  趕緊修改自己的代碼。實現了支持Excel 2010版本。瞬間有種大功告成的感覺,有木有。。O(∩_∩)O哈哈~。好有成就感的說。

複製代碼
 1 public static void Excel2007AboveOperateOld(String filePath) throws IOException {
 2         XSSFWorkbook workbook = new XSSFWorkbook(new FileInputStream(new File(filePath)));
 3         // 獲取第一個表單
 4         Sheet first = workbook.getSheetAt(0);
 5         for (int i = 0; i < 100000; i++) {
 6             Row row = first.createRow(i);
 7             for (int j = 0; j < 11; j++) {
 8                 if(i == 0) {
 9                     // 首行
10                     row.createCell(j).setCellValue("column" + j);
11                 } else {
12                     // 數據
13                     if (j == 0) {
14                         CellUtil.createCell(row, j, String.valueOf(i));
15                     } else
16                         CellUtil.createCell(row, j, String.valueOf(Math.random()));
17                 }
18             }
19         }
20         // 寫入文件
21         FileOutputStream out = new FileOutputStream("workbook.xlsx");
22         workbook.write(out);
23         out.close();
24     }
複製代碼

  趕緊運行跑起來。第一次測試寫入1w條數據。耗時8秒多點。感覺寫入速度好慢,1w條8秒,100w。。我的天。這效率完全不能接受。於是測試10w,看看測試一下是不是真的寫入速度過慢。測試結果讓人崩潰。

1 Cast time : 49699

  測試導出10w條數據到excel耗時將近50秒。於是這種方式被暫時放棄。成就感瞬間被打落在地。

  

  再次回到POI的官網。http://poi.apache.org/spreadsheet/index.html

  官方提到自POI3.8版本開始提供了一種SXSSF的方式,用於超大數據量的操作。於是...

  原文:

  SXSSF is an API-compatible streaming extension of XSSF to be used when very large spreadsheets have to be produced...

  

    馬上開動修改代碼。代碼如下:

複製代碼
 1 public static void Excel2007AboveOperate(String filePath) throws IOException {
 2         XSSFWorkbook workbook1 = new XSSFWorkbook(new FileInputStream(new File(filePath)));
 3         SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook(workbook1, 100);
 4 //            Workbook workbook = WorkbookFactory.create(new FileInputStream(new File(filePath)));
 5         Sheet first = sxssfWorkbook.getSheetAt(0);
 6         for (int i = 0; i < 100000; i++) {
 7             Row row = first.createRow(i);
 8             for (int j = 0; j < 11; j++) {
 9                 if(i == 0) {
10                     // 首行
11                     row.createCell(j).setCellValue("column" + j);
12                 } else {
13                     // 數據
14                     if (j == 0) {
15                         CellUtil.createCell(row, j, String.valueOf(i));
16                     } else
17                         CellUtil.createCell(row, j, String.valueOf(Math.random()));
18                 }
19             }
20         }
21         FileOutputStream out = new FileOutputStream("workbook.xlsx");
22         sxssfWorkbook.write(out);
23         out.close();
24     }
複製代碼

  多次運行測試。查看數據

1 Cast time : 11604

  看到數據的瞬間感覺,哇塞。好給力的說。居然從將近50秒縮短帶11秒。。。

  爲什麼都是代碼差距就這麼大呢?

  原來,SXSSF實現了一套自動刷入數據的機制。當數據數量達到一定程度時(用戶可以自己設置這個限制)。像文本中刷入部分數據。這樣就緩解了程序運行時候的壓力。達到高效的目的。O(∩_∩)O哈哈~

 

  再一次測試單表寫入100w條數據。

1 Cast time : 87782

  將近90秒就完成了100w條數據的寫入。O(∩_∩)O哈哈~。   雖然看上去依舊有一點慢。但是考慮到數據量這樣的耗時,想來已經是可以接受的了。100w條數據生成的Excel表單居然有136mb。打開就這個文檔都花了不少時間。哈哈

  曬一下成就:

  

  

  源碼下載:http://pan.baidu.com/s/1bnw9pYB

  筆者能力有限。暫時只是使用POI類庫實現了相對高效的批量寫入。假如有更好的類庫或者是方法的朋友。歡迎留言分享。多謝指點。。O(∩_∩)O哈哈~   

 

作者:TinyZ
出處:http://www.cnblogs.com/zou90512/
關於作者:努力學習,天天向上。不斷探索學習,提升自身價值。記錄經驗分享。
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接
如有問題,可以通過 [email protected] 聯繫我,非常感謝。
筆者網店: http://aoleitaisen.taobao.com. 歡迎廣大讀者圍觀


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章