在POI导出的时候我们需要根据不同的excel版本,以及预计最大数据量来选择相应的POI工具类.
POI用于操作Excel的对象都是实现了Workbook接口的类.
Workboot是创建Excel对象或Sheet等的顶级对象,有四个子类.
HSSFWorkbook
-
操作Excel2003以前(包括2003)的版本,扩展名是.xls
-
此种方式的局限就是导出的行数至多为65535行,超出65536条后系统就会报错。此方式因为行数不足七万行所以一般不会发生内存不足的情况(OOM)
XSSFWorkbook
- 操作Excel2007后的版本,扩展名是.xlsx
- 这种形式的出现是为了突破HSSFWorkbook的65535行局限。对应的是excel2007(1048576行,16384列)扩展名为“.xlsx”,最多可以导出104万行,不过这样就伴随着一个问题—OOM内存溢出,原因是所创建的book,sheet,row等对象是在内存中的,并没有持久化到磁盘.大数据量情况下项目的运行内存根本不够.
SXSSFWorkbook
- 操作Excel2007后的版本,扩展名是.xlsx
- 对于大型excel文件的创建,一个关键问题就是,要确保不会内存溢出。其实,就算生成很小的excel(比如几Mb),它用掉的内存是远大于excel文件实际的size的。再加上单元格样式之类的,那它占用的内存就更多了。对于大型excel的创建且不会内存溢出的,就只有SXSSFWorkbook了。它的原理很简单,用硬盘空间换内存(就像hash map用空间换时间一样)。
SXSSFWorkbook是streaming版本的XSSFWorkbook,它只会保存最新的excel rows在内存里供查看,在此之前的excel rows都会被写入到硬盘里(Windows电脑的话,是写入到C盘根目录下的temp文件夹)。被写入到硬盘里的rows是不可见的/不可访问的。只有还保存在内存里的才可以被访问到。
SXSSFWorkbookWithCustomZipEntrySource
是SXSSFWorkbook的子类,在构建SXSSFWorkbook对象的时候可以配置是否压缩磁盘中的excel.压缩后磁盘的空间使用率会大大减少,但是队导出的性能就有所影响
重点说下SXSSFWorkbook的相关操作
官方介绍翻译后大致如下:
SXSSF是一个与API兼容的流扩展,在需要生成非常大的电子表格时使用,堆空间有限。SXSSF通过限制对滑动窗口中的行的访问来实现其低内存占用,而XSSF允许访问文档中的所有行。当将旧行写入磁盘时,不再在窗口中的旧行变得不可访问
SXSSFWorkbook构造器:
1.默认构造器
用默认的行窗口大小构造一个新的Workboot对象,默认值为100
2.使用现有模板或者需要在之前Excel后追加
因为SXSSF是XSSF的一个与API兼容的,所以可以用XSSFWorkbook来构建新的模板样式对象,也是没有设置滑动窗口的大小,所以也是默认100.
3.兼容现有模板并且制定滑动窗口大小
rowAccessWindowSize: 窗口大小
可以根据环境配置来设置窗口大小,过大会消耗内存,过小会频繁stream操作.
设置为-1表示不限制内存存储的row数量,若需要刷新在磁盘需手动调用output的flush(),注意:若已刷新不在内存的row不可以通过getRow()来获取了
4.兼容现有模板,自定义窗口大小并且设置临时文件GZIP压缩
5.兼容现有模板,自定义窗口大小并且设置临时文件是否GZIP压缩,设置是否要采用共享字符串表
SharedStringsTable:共享字符串表,当前Workbot中的字符串缓存
根据实际情况来设置,若导出的数据中有大量重复的字符串,则可以设置开启.
引用SharedStringsTable注释:
Consider for example a workbook summarizing information for cities within
<various countries. There may be a * column for the name of the country, a column for the name of each city in that country, and a column * containing the data for each city. In this case the country name is repetitive, being duplicated in many cells. * In many cases the repetition is extensive, and a tremendous savings is realized by making use of a shared string * table when saving the workbook. When displaying text in the spreadsheet, the cell table will just contain an * index into the string table as the value of a cell, instead of the full string.
例如,考虑一个工作簿,它汇总了各个国家/地区中城市的信息。国家名称可能带有某列,该国家/地区中每个城市的名称均带有某列,而每个城市的数据则带有某列。在这种情况下,国家/地区名称是重复的,在许多单元格中重复。 在许多情况下,重复是广泛的,并且在保存工作簿时通过使用共享字符串表可以实现巨大的节省。在电子表格中显示文本时,单元格表将只在字符串表中包含一个索引作为单元格的值,而不是完整的字符串。
6.只设置窗口大小
若没有则创建一个新的XSSFWorkbook对象
以上所有构造都是调用的此构造
👇👇👇👇👇👇
介绍完所有构造,对SXSSFWorkbook的功能作用以及用法有大致了解.
之前说过,如果内存冲存储的row数据超过我们设置的窗口阈值,则会刷新在磁盘的临时文件.可以设置临时文件在磁盘的路径:
默认是系统配置的tmp路径
也可以自定义配置临时路径
调用TempFile的setTempFileCreationStrategy()
小补充:
刚开始用SXSSFWorkbook的时候在想如果临时文件过多会怎么办.会不会自动删除临时文件或者需要我们定时清除.
Workboot对象会在write后帮我们释放磁盘空间
简单示例:
//创建现有模板对象
XSSFWorkbook xss = null;
//Stream处理模板对象
SXSSFWorkbook exl = null;
FileOutputStream out = null;
try(FileInputStream input = new FileInputStream(new File(filePath))) {
xss = new XSSFWorkbook(input);
//构建SXSSF,设置模板和内存保留行数
exl = new SXSSFWorkbook(xss,100);
//更变临时文件目录
TempFile.setTempFileCreationStrategy(new DefaultTempFileCreationStrategy(new File("E:\\Temp")));
//获取Sheet
SXSSFSheet sheet = exl.getSheet("Sheet");
//省略写入excel相关代码
......
//写入execl
out = new FileOutputStream(filePath);
exl.write(outputStream1);
} catch (Exception ex) {
LOGGER.error("Exception is : {}", ex);
} finally {
try {
if (exl != null) {
exl.close();
}
if (out != null) {
out.close();
}
if (xss != null){
xss.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}