天天看點

Apache POI Excel 速度相關

Apache POI Excel速度

POI基本概念

   1. POI針對目前存在的兩種版本的Excel有不同的實作方式.而對于相同版本的Excel又分為Dom解析和Sax解析兩種.而這兩種在記憶體使用,性能各方面均有不同.

  • usermodel,它是基于DOM的文檔驅動,讀寫都支援,基于記憶體的,總之就是很垃圾
  • SAX(simple API for XML)是一種XML解析的替代方法。相比于DOM,SAX是一種速度更快,更有效的方法。它逐行掃描文檔,一邊掃描一邊解析。而且相比于DOM,SAX可以在解析文檔的任意時刻停止解析,但任何事物都有其相反的一面,對于SAX來說就是操作複雜。
  • sxssf,sxssf是xssf的一個與PI相容的流擴充,在需要生成非常大的表格時使用,堆空間有限。SXSSF通過限制對滑動視窗中的行的通路來實作其低記憶體占用,而xssf允許通路文檔中的所有行。它你可了解為緩存流式支援,在寫檔案很重要。

   2.03和07版xls差別?

  • a.支援文檔類型不同
    • 03版: 隻支援xls類型的文檔
                 
    • 07版: 除了支援xls類型文檔,還支援xlsx類型的文檔
                 
  • b.行數限制
    • 03版: 65536行、
                 
    • 07版: 1048576行
                 

大資料量處理

  • 03版:HSSFWorkbook(基于usermodel)
    • 優點:過程中寫入緩存,不操作磁盤,最後一次性寫如磁盤,速度快
                 
    • 缺點:最多隻能處理65536行
                 
  • 07版:XSSFWorkbook(基于usermodel)
    • 優點:可以寫入較大的資料
                 
    • 缺點:寫入資料速度非常慢,非常耗記憶體,也會發生記憶體溢出
                 
  • 更新版:SXSSFWorkbook(基于sxssf)
    • 優點:可以寫非常大的資料量,寫入速度快,占用更少的記憶體
                 
    • 注意:過程中會産生臨時檔案,需清理臨時檔案(.dispose())
                 
    • 預設由100條記錄被儲存再記憶體中,如果超過這個數量,則最前面的資料被寫入到臨時檔案中
                 
    • 如果想自定義記憶體中資料的量,可以使用new SXSSFWorkbool(數量);
                 
    • 它的原理很簡單,用硬碟空間換記憶體(就像hash map用空間換時間一樣)
                 

三種方式資料處理測試

@Test
    public void testCompare03(){
        Long startTime=System.currentTimeMillis();
        //1.建立一個工作簿
        Workbook workbook=new HSSFWorkbook();
        //2.建立一個工作表
        Sheet sheet=workbook.createSheet("第一個工作表");
        int rowNum=65536;
        int cellNum=10;
        for (int i = 0; i < rowNum; i++) {
            //3.建立一行
            Row row=sheet.createRow(i);
            for (int i1 = 0; i1 < cellNum; i1++) {
                //4.建立單元格
                Cell cell=row.createCell(i1);
                cell.setCellValue("你好呀"+i1);
            }
        }
        System.out.println("共耗時"+(System.currentTimeMillis()-startTime)/1000+"秒");
        //生成一張表 03版本使用xls結尾
        try {
            FileOutputStream fileOutputStream=new FileOutputStream("D:"+ File.separator+"excelTest.xls");
            workbook.write(fileOutputStream);
            fileOutputStream.close();
            Long endTime=System.currentTimeMillis();
            System.out.println("生成完畢共耗時:"+(endTime-startTime)/1000+"秒");
        } catch (Exception e) {
            e.printStackTrace();
        }
/*        共耗時0秒
        生成完畢共耗時:2秒*/
    }
           

  可以看到使用HSSFWorkbook測試的是

65536

條資料,最後一次性寫入磁盤,是以速度較為快速。

@Test
    public void testCompare07(){
        Long startTime=System.currentTimeMillis();
        //1.建立一個工作簿
        Workbook workbook=new XSSFWorkbook();
        //2.建立一個工作表
        Sheet sheet=workbook.createSheet("第一個工作表");
        int rowNum=100000;
        int cellNum=10;
        for (int i = 0; i < rowNum; i++) {
            //3.建立一行
            Row row=sheet.createRow(i);
            for (int i1 = 0; i1 < cellNum; i1++) {
                //4.建立單元格
                Cell cell=row.createCell(i1);
                cell.setCellValue("你好呀"+i1);
            }
        }
        System.out.println("共耗時"+(System.currentTimeMillis()-startTime)/1000+"秒");
        //生成一張表 07版本使用xlsx結尾
        try {
            FileOutputStream fileOutputStream=new FileOutputStream("D:"+ File.separator+"excelTest1.xlsx");
            workbook.write(fileOutputStream);
            fileOutputStream.close();
            Long endTime=System.currentTimeMillis();
            System.out.println("07版生成完畢共耗時:"+(endTime-startTime)/1000+"秒");
        } catch (Exception e) {
            e.printStackTrace();
        }
        /*共耗時19秒
         07版生成完畢共耗時:27秒*/
    }
           

  可以看到使用XSSFWorkbook測試的是

100000

條資料,非常耗記憶體,超過1000000條資料也會發生記憶體溢出。

@Test
    public void testCompare07S(){
        Long startTime=System.currentTimeMillis();
        //1.建立一個工作簿
        Workbook workbook=new SXSSFWorkbook(100);
        //2.建立一個工作表
        Sheet sheet=workbook.createSheet("第一個工作表");
        int rowNum=100000;
        int cellNum=10;
        for (int i = 0; i < rowNum; i++) {
            //3.建立一行
            Row row=sheet.createRow(i);
            for (int i1 = 0; i1 < cellNum; i1++) {
                //4.建立單元格
                Cell cell=row.createCell(i1);
                cell.setCellValue("你好呀"+i1);
            }
        }
        System.out.println("共耗時"+(System.currentTimeMillis()-startTime)/1000+"秒");
        //生成一張表 07更新版本使用xlsx結尾
        try {
            FileOutputStream fileOutputStream=new FileOutputStream("D:"+ File.separator+"excelTest1S.xlsx");
            workbook.write(fileOutputStream);
            fileOutputStream.close();
            ((SXSSFWorkbook) workbook).dispose();//清理臨時檔案
            Long endTime=System.currentTimeMillis();
            System.out.println("更新版生成完畢共耗時:"+(endTime-startTime)/1000+"秒");
        } catch (Exception e) {
            e.printStackTrace();
        }
       /*        共耗時3秒
        更新版生成完畢共耗時:5秒*/
    }
           

  可以看到使用SXSSFWorkbook測試的是

100000

條資料,寫資料速度快,占用更少的記憶體,但是過程中會産生臨時檔案,需及時清理。

采用原生api生成excel,都有可能會消耗大量記憶體,例如生成格式、合并單元格等操作。