POI3.8解決導出大數據量excel文件時內存溢出的問題


POI3.8的SXSSF包是XSSF的一個擴展版本,支持流處理,在生成大數據量的電子表格且堆空間有限時使用。SXSSF通過限制內存中可訪問的記錄行數來實現其低內存利用,當達到限定值時,新一行數據的加入會引起老一行的數據刷新到硬盤。

       比如內存中限制行數為100,當行號到達101時,行號為0的記錄刷新到硬盤並從內存中刪除,當行號到達102時,行號為1的記錄刷新到硬盤,並從內存中刪除,以此類推。

       rowAccessWindowSize代表指定的內存中緩存記錄數,默認為100,此值可以通過

new SXSSFWorkbook(int rowAccessWindowSize)或SXSSFSheet.setRandomAccessWindowSize(intwindowSize)來設置。

       SXSSF在把內存數據刷新到硬盤時,是把每個SHEET生成一個臨時文件,這個臨時文件可能會很大,有可以會達到G級別,如果文件的過大對你來說是一個問題,你可以使用下面的方法讓SXSSF來進行壓縮,當然性能也會有一定的影響。

    SXSSFWorkbook wb = new SXSSFWorkbook();

    wb.setCompressTempFiles(true); // temp files will be gzipped

例子:

生成三個SHEET,每個SHEET有6000行記錄,共18萬行記錄

importjava.io.FileOutputStream;
importorg.apache.poi.ss.usermodel.Cell;
importorg.apache.poi.ss.usermodel.Row;
importorg.apache.poi.ss.usermodel.Sheet;
importorg.apache.poi.ss.util.CellReference;
importorg.apache.poi.xssf.streaming.SXSSFSheet;
importorg.apache.poi.xssf.streaming.SXSSFWorkbook; 

public classSXSSFWorkBookUtil {

    public voidtestWorkBook() {

       try{
           longcurr_time=System.currentTimeMillis();
           introwaccess=100;//內存中緩存記錄行數
           /*keep 100 rowsin memory,exceeding rows will be flushed to disk*/
           SXSSFWorkbook wb = newSXSSFWorkbook(rowaccess); 
           intsheet_num=3;//生成3個SHEET

           for(inti=0;i<sheet_num;i++){
              Sheet sh = wb.createSheet();
              //每個SHEET有60000ROW
              for(intrownum = 0; rownum < 60000; rownum++) {
                  Row row = sh.createRow(rownum);
                  //每行有10個CELL
                  for(intcellnum = 0; cellnum < 10; cellnum++) {
                     Cell cell = row.createCell(cellnum);
                     String address = newCellReference(cell).formatAsString();
                     cell.setCellValue(address);
                  }
                  //每當行數達到設置的值就刷新數據到硬盤,以清理內存
                  if(rownum%rowaccess==0){
                     ((SXSSFSheet)sh).flushRows();
                  }
              }
           }

           /*寫數據到文件中*/
           FileOutputStream os = newFileOutputStream("d:/data/poi/biggrid.xlsx");    
           wb.write(os);
           os.close();
           /*計算耗時*/
           System.out.println("耗時:"+(System.currentTimeMillis()-curr_time)/1000);
       } catch(Exception e) {
           e.printStackTrace();
       }
    }
}

 

 

對於不同的rowAccessWindowSize值,用上面的例子進行耗時測試,結果如下:

 

rowAccessWindowSize    Time(s)

5000    293

1000    69

500    43

100    20

50    18

10    16

1    15

 

 

以上測試結果是在個人筆記本電腦上進行的,配置為:

Dual-Core CPU T4400 2.2GHz 2.19GHz

Memory 1.86GB

以上測試過程只是進行了一次,並沒有多次測試求平均值,數據也只想表達當設置不同的rowAccessWindowSize值,耗時的一種趨勢。

可見一般情況下,使用默認值100即可。

 

參考 http://xtadg.iteye.com/blog/1703572

 http://javaflex.iteye.com/blog/1264127

 

2016-11-23

poi讀取excel時

hssfSheet.getLastRowNum();//最后一行行標,比行數小1

hssfSheet.getRow(k).getLastCellNum();//獲取列數,比最后一列列標大1


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM