背景
一般Java会使用ApachePOI作为xlsx的默认读取和写入工具包,因为XSSFWorkbook 和XSSFSheet使用了DOM作为xml的解析技术,所以读取时默认会将整个sheet的内容加载到java JVM内存中,所以在超大数据量Excel的生成和读取都是非常消耗资源的操作,本文的方案使用了JDK1.6引入的StAX 相关的技术,以stream方式读取超大的Excel文件,避免了JVM内存占用开销,提高了处理速度。
相关技术栈
1.DOM/SAX/StAX相关介绍
详细技术内容可以看相关文章
https://cloud.tencent.com/developer/article/2423715
https://mkyong.com/java/how-to-read-xml-file-in-java-stax-parser/
2.关于POI的SAX方式解析
https://howtodoinjava.com/java/library/poi-read-excel-with-sax-parser/
实现思路
1.需借助poi 的OPCPackage。OPCPackage 是 Apache POI 提供的一个用于处理 Open XML 格式文档的包;
2.使用XSSFReader类,XSSFReader这个类可以很容易地获得OOXML .xlsx文件的各个部分,适用于低内存sax解析或类似的情况;
3.xssfReader.getSheetsData()方法,获取Sheet的流迭代器;
4.使用Stax API,以stream的方式读取sheet对应的XML
接口约定和注意事项
1.调用对应API需定义XLSX文件的元数据信息;
2.接口调用传入Inputstream,而非File或FileInputStream,因为该接口不限于读取本地文件,只需要能支持流方式读取的FileSystem都可以适用;
3.使用StAX时候需要添加相应的约束,以防止XML的XXE注入攻击可能;
4.因无法使用POI的Sheet和Cell,读取出来的数据均为String,相应的CellType和日期处理需要单独进行处理;
5.因为使用迭代器接口返回,OPCPackage和对应的Stream不能使用 try with resource编码,需要在读取完成后手动进行关闭;
具体实现
实现工具类
代码片段
public class XlsxFileIterator extends AbstractFileIterator{
private XMLInputFactory factory;
private XMLStreamReader streamReader;
private OPCPackage opcPackage;
private Iterator<InputStream> sheetStreams;
private InputStream readStreams;
private XSSFReader xssfReader;
private SharedStrings sharedStrings;
......
@Override
public void beforeProcess() {
super.beforeProcess();
try {
//防 XXE注入
factory = XMLInputFactory.newFactory();
factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE);
factory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
opcPackage=OPCPackage.open(instream);
xssfReader=new XSSFReader(opcPackage);
sheetStreams=xssfReader.getSheetsData();
sharedStrings=xssfReader.getSharedStringsTable();
......
}catch (Exception ex){
}
}
private void readNext() throws Exception{
String nodeName;
int rowNum;
String rowNumStr;
int columnPos=0;
String value;
boolean sharedValue=false;
boolean breakTag=false;
Object targetValue=null;
while (streamReader.hasNext() && !breakTag){
......
}
}
}
说明
1.AbstractFileSystemAccessor 负责文件系统读取输入XLSX文件,返回InputStream,对应的FileSystem包含Local、HDFS、ApacheVFS支持的FileSystem,以及各类云存储(Aliyun、TencentCos等);
2.DataCollectionMeta 通用元数据定义,包含数据项和资源类型以及相关参数;
3.目前版本暂不支持公式字段的计算,需要生成的XLSX文件中公式字段包含结果值;
4.后续支持公式计算,也只能支持本行内操作,跨行因为是迭代器模式无法支持;
5.后续公式因无法调用POI的API,也仅能支持四则运算相关;
调用实例
中的testReadWithIterator 测试方法
测试需要的实例数据可以调用该类的testGenerate方法