今天,一朋友問我使用JAVA有沒有什麼辦法導出百萬級的數據到Excel工做表。html
當時個人第一個念頭就是這真的是一個好瘋狂的念頭。而後就想假如真的有這樣相似的需求,我本身應該怎麼作呢?java
ps: 首先科普一下基礎知識apache
Excel 2003及如下的版本。一張表最大支持65536行數據,256列。也就是說excel2003徹底不可能知足百萬數據導出的需求。app
Excel 2007-2010版本。一張表最大支持1048576行,16384列;dom
筆者使用的是office 2010,更高的版本筆者沒有使用過,暫時沒法判斷。socket
由此看來百萬級的數據量對Excel自身已是屬於接近極限的程度。xss
假如咱們有更大的需求怎麼辦呢?maven
既然單表支持最大是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/
關於做者:努力學習,每天向上。不斷探索學習,提高自身價值。記錄經驗分享。
本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文連接
若有問題,能夠經過 zou90512@126.com 聯繫我,很是感謝。
筆者網店: shop70768633.taobao.com. 歡迎廣大讀者圍觀