今天项目中有个需要 Excel 导出的需求。看了下同事用了 SXSSFWorkbook 。之前没怎么用到这个组件。既然这次用了就简单分析一下。
POI提供了HSSF、XSSF以及SXSSF三种方式操作Excel。他们的区别如下:
1 | 复制代码HSSF:是操作Excel97-2003版本,扩展名为.xls。 |
本文的重点就是分析一下,SXSSF如何支持低内存占用的。
先说结论:SXSSF 指定了rowAccessWindowSize ,每个sheet 对应一个临时文件,当行数大于rowAccessWindowSize 时,就会向临时文件中flush, 这样就保证了内存的低占用率。当行创建完,直接从临时文件中写入到Excel中。
有一点需要注意:像单元格合并类似的操作是纯内存操作,如果项目中想一次合并多行时,要注意随时观察自己机器内容的使用情况,避免出现OOM。
1 来个demo
1 | 复制代码 // 内存中保持100条数据, 超出的部分刷新到磁盘上 |
2 主要分析点
2.1 创建SXSSFWorkbook
如demo所示, SXSSFWorkbook wb = new SXSSFWorkbook(100);
中指定了rowAccessWindowSize 为100 ,也就是说
会在内存中缓存 rowAccessWindowSize 行数据。当行数超过 rowAccessWindowSize ,则会从内存输入到临时文件中。
临时文件的生成在
2.2 创建Sheet
部分 讲一下。超过阈值刷入临时文件在2.3 创建row
部分讲解。
2.2 创建Sheet
如demo所示,Sheet sh = wb.createSheet();
创建了Sheet. 那么创建过程中,主要的功能是创建了一个临时文件。每个sheet 一个临时文件。废话不多说,我们来看下createSheet的实现。
1 | 复制代码public SXSSFSheet createSheet() { |
createAndRegisterSXSSFSheet 中最核心的就是 sxSheet = new SXSSFSheet(this, xSheet);
。那我们来看下这个函数:
1 | 复制代码public SXSSFSheet(SXSSFWorkbook workbook, XSSFSheet xSheet) throws IOException { |
createSheetDataWriter 中核心的逻辑是 SheetDataWriter。看到createTempFile ,这儿就创建了临时文件。
1 | 复制代码public SheetDataWriter() throws IOException { |
关于临时文件:
前缀:poi-sxssf-sheet 后缀:.xml
存储路径:代码如下
1 | 复制代码private void createPOIFilesDirectory() throws IOException { |
2.3 创建row
什么时间从内存写入文件?就是在创建row时。那我们看下代码:
1 | 复制代码public SXSSFRow createRow(int rownum) { |
判断逻辑就在这儿if (this._randomAccessWindowSize >= 0 && this._rows.size() > this._randomAccessWindowSize)
。
下面几部分跟低内存占用没有关系了,只是分析一下在项目中实际用的几个步骤。
2.4 从临时文件写入最终Excel
写入Excel 主要是在workbook.write(out)
。看下代码:
1 | 复制代码public void write(OutputStream stream) throws IOException { |
基本逻辑很简洁:
(1)将内存中剩余不足randomAccessSize 数目的数据,先写入sheet 临时文件。
(2)将workbook 中所有的数据(就是多个sheet临时文件)写入一个 刚刚创建的tmpl临时文件
(3)将tmpl临时文件 的数据写入目标文件即可。
2.5 删除临时文件
workbook.dispose();
这儿的逻辑。
1 | 复制代码public boolean dispose() { |
基本的逻辑是,遍历多个sheet, 然后对每个sheet执行dispose . dispose 的逻辑就是如果还没文件没有从sheet中输出,则先flush,然后删除sheet临时文件。
2.6 关于合并单元格的操作
单元格合并的用法:
1 | 复制代码 CellRangeAddress region0 = new CellRangeAddress(rowNum, rowNum+1, column, column); |
这儿就是根据 rowNum 跟column进行合并而已。
1 | 复制代码private int addMergedRegion(CellRangeAddress region, boolean validate) { |
3 总结
本文结合项目中用到的Excel 工具- SXSSFWorkbook ,进行了简单讲解。并针对SXSSFWorkbook 低内存占用部分进行了分析。希望对你有所帮助~
本文同步发布在简书 www.jianshu.com/p/18046332b…
4 参考文献
HSSF、XSSF和SXSSF区别以及Excel导出优化
www.cnblogs.com/pcheng/p/74…
基于流的EXCEL文件导出,SXSSFWorkbook源码解析
www.jianshu.com/p/b80a20b81…
#5 其他
(1)读取excel 数字时,默认会带一个 “.0” ,怎么解决?
my.oschina.net/henglaixuex…
本文转载自: 掘金