聊聊Excel解析:如何处理百万行EXCEL文件?( 六 )


System.out.println( "全部解析完成");
}
}).sheet.doRead;
}
}
测验一下,用它解析一个十万行的 excel,该文件用 UserModel 读取会 OOM,如下:

聊聊Excel解析:如何处理百万行EXCEL文件?

文章插图
运行结果:
聊聊Excel解析:如何处理百万行EXCEL文件?

文章插图
(4)Xlsx-streamerXlsx-streamer 简介
Xlsx-streamer 是一款用于流式读取 Excel 的工具,同样基于 POI 二次开发 。虽然 EasyExcel 可以很好地解决 Excel 读取的问题,但解析方式为 SAX,需要通过实现监听器以事件驱动的方式进行解析 。有没有其他的解析方式呢?Xlsx-streamer 给出了答案 。
译自官方文档的描述:
如果您过去曾使用 Apache POI 读取 Excel 文件,您可能会注意到它的内存效率不是很高 。阅读整个工作簿会导致严重的内存使用高峰,这会对服务器造成严重破坏 。Apache 必须读取整个工作簿的原因有很多,但其中大部分与该库允许您使用随机地址进行读写有关 。如果(且仅当)您只想以快速且内存高效的方式读取 Excel 文件的内容,您可能不需要此功能 。不幸的是,POI 库中唯一用于读取流式工作簿的东西要求您的代码使用类似 SAX 的解析器 。该 API 中缺少所有友好的类,如 Row 和 Cell 。该库充当该流式 API 的包装器,同时保留标准 POI API 的语法 。继续阅读,看看它是否适合您 。注意:这个库只支持读取 XLSX 文件 。
如介绍所言,Xlsx-streamer 最大的便利之处是兼容了用户使用 POI UserModel 的习惯,它对所有的 UserModel 接口都给出了自己的流式实现,如 StreamingSheet、StreamingRow 等,对于熟悉 UserModel 的开发者来说,几乎没有学习门槛,可以直接使用 UserModel 访问 Excel 。
Xlsx-streamer 的实现原理和 SXSSF 相同,都是滑动窗口 —— 限定读入内存中的数据大小,将正在解析的数据读到内存缓冲区中,形成一个临时文件,以防止大量使用内存 。缓冲区的内容会随着解析的过程不断变化,当流关闭后,临时文件也将被删除 。由于内存缓冲区的存在,整个流不会被完整地读入内存,从而防止了内存溢出 。
与 SXSSF 一样,因为内存中仅加载入部分行,故牺牲了随机访问的能力,仅能通过遍历顺序访问整表,这是不可避免的局限 。换言之,如果调用 StreamingSheet.getRow (int rownum) 方法,该方法会获取 sheet 的指定行,会抛出 “不支持该操作” 的异常 。
Xlsx-streamer 最大的优势是兼容 UserModel,尤其适合那些熟悉 UserModel 又不想使用繁琐的 EventModel 的开发者 。它和 SXSSF 一样,都通过实现 UserModel 接口的方式给出解决内存问题的方案, 很好地填补了 SXSSF 不支持读取的空白,可以说它是 “读取版” 的 SXSSF 。
使用 Xlsx-streamer
引入 pom 依赖:
< dependency>
< groupId> com.monitorjbl </ groupId>
< artifactId> xlsx-streamer </ artifactId>
< version> 2.1.0 </ version>
</ dependency>
下面是一个使用 xlsx-streamer 的 demo:
importcom.monitorjbl.xlsx.StreamingReader;
importorg.apache.poi.ss.usermodel.Cell;
importorg.apache.poi.ss.usermodel.Row;
importorg.apache.poi.ss.usermodel.Sheet;
importorg.apache.poi.ss.usermodel.Workbook;
importjava.io.FileInputStream;
publicclassMyXlsxStreamer{
publicstaticvoid main( String[] args) throwsException{
parseSku;
}
publicstaticvoid parseSku throwsException{
FileInputStreamin= new FileInputStream( "D:sunhaoyu8DocumentsFilesexcel.xlsx");
Workbookwk = StreamingReader.builder
//缓存到内存中的行数,默认是10
.rowCacheSize( 100)
//读取资源时,缓存到内存的字节大小,默认是1024
.bufferSize( 4096)
//打开资源,必须,可以是InputStream或者是File
. open( in);
Sheetsheet = wk.getSheetAt( 0);
for( Rowr : sheet) {
System.out. print( "第"+ r.getRowNum + "行:");
for( Cellc: r) {
if( c!= null) {
System.out. print( c.getStringCellValue + " ");
}
}
System.out. println;
}
}
}
如代码所示,Xlsx-streamer 的使用方法为:使用 StreamingReader 进行参数配置和流式读取,我们可以手动配置固定的滑动窗口大小,有两个指标,分别是缓存在内存中的最大行数和缓存在内存的最大字节数,这两个指标会同时限制该滑动窗口的上限 。接下来,我们可以使用 UserModel 的 API 去遍历访问读到的表格 。


推荐阅读