使用POI解析Excel
1、OpenXML标准
Word、Excel、PPT是Office办公套件中最常用的三个组件。早期的Office套件使用二进制格式,这里面包括以.doc、.xls、.ppt为后缀的文件;直到07这个划时代的版本将基于XML的压缩格式作为默认文件格式,也就是相应以.docx、.xlsx、.pptx为后缀的文件。
这个结合了XML与Zip压缩技术的新文件格式使用的是OpenXML标准。微软从2000年开始酝酿这项技术标准,到2006年申请成为ECMA-376,然后在Office2007中用作默认的文件格式,再到08年成为了ISO / IEC 29500国际标准,后续每两三年就会发布一个新版本。Office的一路凯歌无不彰显微软雄厚的实力。
所以说三流公司做产品,二流公司做平台,一流公司定标准。
微软的官方文档中详细介绍了WordprocessingML(Word)、SpreadsheetML(Excel)、PresentationML(PPT)三个标准,这里主要介绍Excel的部分内容。
首先Excel几个最基础的概念:
一个Excel就是一个工作簿(Workbook)
一个Sheet就是一张表格
一个Workbook可以包含多个Sheet
每一行Row的每一列就是一个单元格(Cell)
因为07版后的.xlsx本质上就是一个压缩包,我们完全可以用解压工具打开它。
一个基础的Excel解压之后
更典型的Excel还包括:数字、文本、公式、图表(Chart)、普通列表(Table)、数据透视表(Pivot Table)等内容。
Excel远比我们想象的复杂
2、使用POI操作Excel
Java领域最常见的两个操作Excel的工具库分别是JXL(Java Excel API)和Apache的POI。JXL有个严重的缺点就是只支持07版本之前的二进制格式Excel,而POI除了能操作Excel,还可以操作Word和PPT以及Office套装中其他的组件,高下立现。
POI全称是Poor Obfuscation Implementation,简洁模糊实现,也有人翻译成糟糕的模糊实现。
POI目前最新版本是4.0,可以将相应maven依赖添加到pom.xml文件中:
复制代码
org.apache.poi poi 4.0.0 org.apache.poi poi-ooxml 4.0.0 复制代码 POI提供了三种读写Excel的方式:HSSF XSSF SXSSF
1、HSSF支持.xls为后缀的二进制格式,并提供了流解析模式的HSSFListener相关API以及基于内存模型的HSSFWorkbook相关API。
2、XSSF支持.xlsx为后缀的OpenXML格式。因为是底层文件是XML所以可以使用SAX解析,POI提供了XSSFReader用来获取压缩包中的各个XML文件相应的输入流;另外提供了基于DOM解析模式的XSSFWorkbook相关API。
3、POI3.8后提供了SXSSF API,它是基于XSSF构建的低内存占用版本(使用滑动窗口机制来实现低内存访问)。但是需要注意的是SXSSFWorkbook默认使用内联字符串而不是共享字符串表(SharedStringsTable),这样可以让保存在内存中的数据尽可能更少(SharedStringsTable需要常驻内存),所以如果是自己写SAX解析要注意兼容性。
POI滑动窗口只窗口范围内的单元格数据加载到内存中,窗口外的数据读写内容会以临时文件的形式保存到磁盘上,同时还支持临时文件的压缩。SXSSF可以通过构造函数中的rowAccessWindowSize参数指定窗口大小,
compressTmpFiles指定是否压缩临时文件,useSharedStringsTable指定是否使用共享字符表。
2.1、使用Workbook API
上面说的三种方式都有一个Workbook实现类,用法上基本一致。唯一不同的是SXSSFWorkbook最后需要调用dispose()方法处理磁盘上的临时文件。
下面是使用XSSFWorkbook读取.xlsx文件的例子:
// 打开指定位置的Excel文件
FileInputStream file = new FileInputStream(new File(fileLocation));
Workbook workbook = new XSSFWorkbook(file);
// 打开Excel中的第一个Sheet
Sheet sheet = workbook.getSheetAt(0);
// 读取Sheet中的数据
Map<Integer, List<String>> data = new HashMap<>();
int i = 0;
for (Row row : sheet) { // 行
data.put(i, new ArrayList<String>());
for (Cell cell : row) { // 单元格
switch (cell.getCellType()) { // 不同的数据类型
case STRING: ... break; // 字符串类型
case NUMERIC: ... break; // 数值类型
case BOOLEAN: ... break; // 布尔类型
case FORMULA: ... break; // 公式类型
case BLANK: ... break; // 空白类型
}
}
i++;
}
POI有不同的方法来读取每种类型的数据:
switch(cel