1.Excel 2003和 Excel 2007版本的区别?

1.1 文件的后缀名不一样

.xls是03版本文件的后缀名
.xlsx是07版本文件的后缀名
在这里插入图片描述

1.2 最高行数不一样

03版本的最高行数是65536行
在这里插入图片描述
但是07版本的行数没有限制
在这里插入图片描述

2.使用时不区分Excel 2003和 Excel 2007版本有什么后果?

  如果我们在项目中使用POI进行表格数据的读写操作的时候没有注意区分要使用03版本还是07版本,那么很有可能会出现如下异常:

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)

一般出现这种异常的时候首先检查我们在java代码中创建的WorkBook工作簿对象的具体实例是不是HSSFWorkbook
在这里插入图片描述
如果是的话,将HSSFWorkbook修改为XSSFWorkbook

3. POI是什么?

  POI是 Apache基金会用java编写的免费开源的跨平台的Java API,Apache POI向java程序提供 读写Microsoft Office(Excel 、Word、 PPT……)的功能。

基本功能 描述
HSSF 提供读写Microsoft Excel XLS格式档案的功能(2003)
XSSF 提供读写Microsoft Excel OOXML XLSX格式档案的功能(2007)
HWPF 提供读写Microsoft Word DOC97格式档案的功能
XWPF 提供读写Microsoft Word DOC2003格式档案的功能
HSLF 提供读写Microsoft PowerPonit格式档案的功能
HDGF 提供读写Microsoft Visio格式档案的功能
HPBF 提供读写Microsoft Publisher格式档案的功能
HSMF 提供读写Microsoft Outlook格式档案的功能

5. 使用POI为什么会出现OOM现象?

  虽然POI是提供了操作Microsoft Office的功能,但是我们使用最多的还是操作Excel的功能,使用POI来对Excel数据进行解析的时候,是一次性将所有的数据全部加载到内存中进行解析,这样就会占用大量的内存,如果数据量超出了可分配内存空间,则会出现OOM的异常。

But!

虽然使用POI的方式有可能会出现OOM的情况,但是它快啊!!!将数据加载到内存中解析就会将解析之后的数据一次性返回。

现在常见的解决OOM现象的方式可以使用阿里的EasyExcel工具来解决

EasyExcel的GitHub地址:https://github.com/alibaba/easyexcel
在这里插入图片描述

5. POI和EasyExcel的区别?

  总的来说其实EasyExcel就是使用了时间换空间的理念来解决POI的OOM现象。两者没有孰优孰劣,可以根据业务中需要解析的数据量的大小来选择使用哪种方式。

POI:

解析速度快,但是解析数据量比大的时候容易出现OOM现象

EasyExcel:

解析的时候并不是将数据全部加载到内存中,而是逐行解析数据,解析一行数据返回一行数据,所以相对于POI的方式效率较低,但是比较稳定

6. 整个简单的Excel写操作

引入依赖:


    <!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
    <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi</artifactId>
      <version>3.17</version>
    </dependency>

    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
    <dependency>
      <groupId>org.apache.poi</groupId>
      <artifactId>poi-ooxml</artifactId>
      <version>3.17</version>
    </dependency>

进行测试:

package org.magic.excel;

import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.junit.jupiter.api.Test;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.impl.FootnotesDocumentImpl;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class ExcelApplicationTests {

  private static final String path="E:\\private_project\\excel\\src\\test\\java\\org\\magic\\excel";

  @Test
  void write2003() throws IOException {

    long begin_03 = System.currentTimeMillis();
    //创建工作簿
    Workbook workbook = new HSSFWorkbook();
    //创建sheet表
    Sheet sheet = workbook.createSheet("商品信息表");
    for (int rowNum = 0; rowNum < 65536; rowNum++) {
      //创建行row
      Row row1 = sheet.createRow(rowNum);
      //创建列 (坐标为0,0的单元格)
      for (int cellNum = 0; cellNum <6; cellNum++) {
        Cell cell = row1.createCell(cellNum);
        cell.setCellValue(cellNum);
      }
    }
    FileOutputStream fileOutputStream = new FileOutputStream(path+"商品信息表.xls");
    workbook.write(fileOutputStream);
    fileOutputStream.close();

    long end_03 = System.currentTimeMillis();

    System.out.println("03版本消耗时间"+(end_03-begin_03)/1000+"秒");


  }



  @Test
  void write2007() throws IOException {

    long begin_07 = System.currentTimeMillis();

    //创建工作簿
    Workbook workbook = new XSSFWorkbook();
    //创建sheet表
    Sheet sheet = workbook.createSheet("商品信息表");
    for (int rowNum = 0; rowNum < 65536; rowNum++) {
      //创建行row
      Row row1 = sheet.createRow(rowNum);
      //创建列 (坐标为0,0的单元格)
      for (int cellNum = 0; cellNum <6; cellNum++) {
        Cell cell = row1.createCell(cellNum);
        cell.setCellValue(cellNum);
      }
    }
    FileOutputStream fileOutputStream = new FileOutputStream(path+"商品信息表.xlsx");
    workbook.write(fileOutputStream);
    fileOutputStream.close();

    long end_07 = System.currentTimeMillis();
    System.out.println("07版本消耗时间"+(end_07-begin_07)/1000+"秒");

  }

 @Test
  void writeBigData2007() throws IOException {

    long begin_07 = System.currentTimeMillis();

    //创建工作簿
    Workbook workbook = new SXSSFWorkbook();
    //创建sheet表
    Sheet sheet = workbook.createSheet("商品信息表");
    for (int rowNum = 0; rowNum < 65536; rowNum++) {
      //创建行row
      Row row1 = sheet.createRow(rowNum);
      //创建列 (坐标为0,0的单元格)
      for (int cellNum = 0; cellNum <6; cellNum++) {
        Cell cell = row1.createCell(cellNum);
        cell.setCellValue(cellNum);
      }
    }
    FileOutputStream fileOutputStream = new FileOutputStream(path+"商品信息表.xlsx");
    workbook.write(fileOutputStream);
    //清除临时文件
    boolean dispose = ((SXSSFWorkbook) workbook).dispose();
    System.out.println("是否删除临时文件:"+dispose);
    fileOutputStream.close();

    long end_07 = System.currentTimeMillis();
    System.out.println("07版本处理大数据版本消耗时间"+(end_07-begin_07)/1000+"秒");

  }
}

7. 三种Workbook的区别?

在这里插入图片描述

  在上述得案例中,创建Workboot工作薄得时候分别使用了三种不同得具体实例:HSSFWorkbookXSSFWorkbookSXSSFWorkbook

HSSFWorkbook:
  针对于Excel2003版本,创建得工作簿得最高行数为65536行,创建的表格后缀名为.xls也正因为HSSFWorkbook对于数据行数有限制,所以较少会出现OOM内存溢出的情况。

XSSFWorkbook:
  针对于Excel2007版本,创建的工作薄支持的行数为1048576行,创建的表格后缀名为.xlsx一个表的数据量达到104万行,因为解析数据的时候POI是直接将所有的数据全部加载到内存中进行解析,这样就会占用大量的内存,所以此种类型最容易出现OOM

SXSSFWorkbook:
  从POI3.8开始提供SXSSFWorkbook,相当于是2007的一个升级版,专门处理解析大数据量的Excel,避免出现OOM内存溢出。

原理:硬盘空间换内存空间

SXSSFWorkbook只会保存最新(默认是100条)的excel rows在内存中可供查看,在此之前的excel rows会被写入磁盘临时文件中(c盘的temp中),而磁盘中的rows是不可见、不可访问的。只有内存中的rows可以查看。

posted on 2020-04-24 17:15  无关痛痒qaq  阅读(162)  评论(0编辑  收藏  举报