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工作薄得时候分别使用了三种不同得具体实例:HSSFWorkbook
、XSSFWorkbook
、SXSSFWorkbook
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可以查看。