開源工具:百萬級別excel導出easyExcel

開源工具:百萬級別excel導出easyExcel

easyexcel要去解決的問題

1.Excel讀寫時候內存溢出

雖然POI是目前使用最多的用來做excel解析的框架,但這個框架並不那麼完美。大部分使用POI都是使用他的userModel模式。userModel的好處是上手容易使用簡單,隨便拷貝個代碼跑一下,剩下就是寫業務轉換了,雖然轉換也要寫上百行代碼,相對比較好理解。然而userModel模式最大的問題是在於非常大的內存消耗,一個幾兆的文件解析要用掉上百兆的內存。現在很多應用採用這種模式,之所以還正常在跑一定是併發不大,併發上來後一定會OOM或者頻繁的full gc。

2.其他開源框架使用複雜

對POI有過深入瞭解的估計才知道原來POI還有SAX模式。但SAX模式相對比較複雜,excel有03和07兩種版本,兩個版本數據存儲方式截然不同,sax解析方式也各不一樣。想要了解清楚這兩種解析方式,才去寫代碼測試,估計兩天時間是需要的。再加上即使解析完,要轉換到自己業務模型還要很多繁瑣的代碼。總體下來感覺至少需要三天,由於代碼複雜,後續維護成本巨大。

3.其他開源框架存在一些BUG修復不及時

由於我們的系統大多數都是大併發的情況下運行的,在大併發情況下,我們會發現poi存在一些bug,如果讓POI團隊修復估計遙遙無期了。所以我們在easyexcel對這些bug做了規避。 如下一段報錯就是在大併發情況下poi拋的一個異常。

Caused by: java.io.IOException: Could not create temporary directory '/home/admin/dio2o/.default/temp/poifiles'
 at org.apache.poi.util.DefaultTempFileCreationStrategy.createTempDirectory(DefaultTempFileCreationStrategy.java:93) ~[poi-3.15.jar:3.15]
 at org.apache.poi.util.DefaultTempFileCreationStrategy.createPOIFilesDirectory(DefaultTempFileCreationStrategy.java:82) ~[poi-3.15.jar:3.15]

報錯地方poi源碼如下

 private void createTempDirectory(File directory) throws IOException {
 if (!(directory.exists() || directory.mkdirs()) || !directory.isDirectory()) {
 throw new IOException("Could not create temporary directory '" + directory + "'");
 }
 }

仔細看代碼容易明白如果在併發情況下,如果2個線程同時判斷directory.exists()都 為false,但執行directory.mkdirs()如果一些線程優先執行完,另外一個線程就會返回false。最終 throw new IOException("Could not create temporary directory '" + directory + "'")。針對這個問題easyexcel在寫文件時候首先創建了該臨時目錄,避免poi在併發創建時候引起不該有的報錯。

Excel格式分析格式分析

  • xls是Microsoft Excel2007前excel的文件存儲格式,實現原理是基於微軟的ole db是微軟com組件的一種實現,本質上也是一個微型數據庫,由於微軟的東西很多不開源,另外也已經被淘汰,瞭解它的細節意義不大,底層的編程都是基於微軟的com組件去開發的。
  • xlsx是Microsoft Excel2007後excel的文件存儲格式,實現是基於openXml和zip技術。這種存儲簡單,安全傳輸方便,同時處理數據也變的簡單。
  • csv 我們可以理解為純文本文件,可以被excel打開。他的格式非常簡單,解析起來和解析文本文件一樣。

核心原理

寫有大量數據的xlsx文件時,POI為我們提供了SXSSFWorkBook類來處理,這個類的處理機制是當內存中的數據條數達到一個極限數量的時候就flush這部分數據,再依次處理餘下的數據,這個在大多數場景能夠滿足需求。 讀有大量數據的文件時,使用WorkBook處理就不行了,因為POI對文件是先將文件中的cell讀入內存,生成一個樹的結構(針對Excel中的每個sheet,使用TreeMap存儲sheet中的行)。如果數據量比較大,則同樣會產生
java.lang.OutOfMemoryError: Java heap space錯誤。POI官方推薦使用“XSSF and SAX(event API)”方式來解決。 分析清楚POI後要解決OOM有3個關鍵。

1、文件解壓文件讀取通過文件形式

開源工具:百萬級別excel導出easyExcel

2、避免將全部全部數據一次加載到內存

採用sax模式一行一行解析,並將一行的解析結果以觀察者的模式通知處理。

開源工具:百萬級別excel導出easyExcel

3、拋棄不重要的數據

Excel解析時候會包含樣式,字體,寬度等數據,但這些數據是我們不關係的,如果將這部分數據拋棄可以大大降低內存使用。Excel中數據如下Style佔了相當大的空間。

github直達:
https://github.com/alibaba/easyexcel


分享到:


相關文章: