對于大型excel檔案的建立,一個關鍵問題就是,要確定不會記憶體溢出。其實,就算生成很小的excel(比如幾Mb),它用掉的記憶體是遠大于excel檔案實際的size的。如果單元格還有各種格式(比如,加粗,背景标紅之類的),那它占用的記憶體就更多了。
對于大型excel的建立且不會記憶體溢出的,就隻有SXSSFWorkbook了。它的原理很簡單,用硬碟空間換記憶體(就像hash map用空間換時間一樣)。
SXSSFWorkbook是streaming版本的XSSFWorkbook,它隻會儲存最新的excel rows在記憶體裡供檢視,在此之前的excel rows都會被寫入到硬碟裡(Windows電腦的話,是寫入到C槽根目錄下的temp檔案夾)。被寫入到硬碟裡的rows是不可見的/不可通路的。隻有還儲存在記憶體裡的才可以被通路到。
至于多少行儲存在記憶體裡,其他寫入硬碟,是由DEFAULT_WINDOW_SIZE決定的。代碼也可以在建立SXSSFWorkbook執行個體時,傳入一個int參數,來設定。需注意的是,int rowAccessWindowSize如果傳入100,并不是指100行儲存在記憶體裡,而是說100的螢幕尺寸下可見的行數。
//Construct a new workbook with default row window size
SXSSFWorkbook test1 = new SXSSFWorkbook();
//Construct an empty workbook and specify the window for row access.
SXSSFWorkbook test2 =new SXSSFWorkbook(int rowAccessWindowSize);
上個疊代,我的任務就是要解決潛在的從DB讀資料寫Excel溢出的問題。資料條數從幾萬到幾十萬條不等(每一行每個單元格還帶格式),加上虛拟機配置很一般,就可能記憶體溢出。使用SXSSFWorkbook,最大生成到800Mb的Excel,都順暢的很。當然了,實際工作中應該不會用到這麼大的excel…一般的機器光是打開就可能卡死,幾乎不可讀。
以下是一些在虛拟機裡的運作結果(均包含從DB讀資料的時間):
int rowAccessWindowSize = 200;
2Mb的excel, 5秒完成
70Mb的excel,2分半完成
800Mb的excel,65分鐘完成
還有一點值得一提,當時為了生成這800Mb的excel,我愣是把C槽清出來10個G的空間,不然SXSSFWorkbook會把硬碟空間全部寫滿,隻剩幾十kb,然後程式僵死…
另外,在Windows + Eclipse開發環境下,可以更改eclipse.ini來配置設定更多記憶體空間給java程式。在Eclipse根目錄下,有個eclipse.ini檔案,用文本編輯器打開,找到-vmargs這一行,修改它下面的參數,儲存,重新開機eclipse即可:
-Xms 預設是實體記憶體的1/64
-Xmx 預設是實體記憶體的1/4
下期博文預告:搭建WebUI自動化架構…