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


为什么 UserModel 支持我们进行如此丰富的操作?因为在 UserModel 中,Excel 中的所有 XML 节点都被解析成了一棵 DOM 树,整棵 DOM 树都被加载进内存,因此可以进行方便地对每个 XML 节点进行 随机访问 。

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

文章插图
UserModel 数据转换
了解了用户模型,我们就可以直接使用其 API 进行各种 Excel 操作 。当然,更方便的办法是使用用户模型将一个 Excel 文件转化成我们想要的 Java 数据结构,更好地进行数据处理 。
我们很容易想到关系型数据库 —— 因为二者的实质是一样的 。类比数据库的数据表,我们的思路就有了:
  1. 将一个 Sheet 看作表头和数据两部分,这二者分别包含表的结构和表的数据 。
  2. 对表头(第一行),校验表头信息是否和实体类的定义的属性匹配 。
  3. 对数据(剩余行),从上向下遍历每一个 Row,将每一行转化为一个对象,每一列作为该对象的一个属性,从而得到一个对象列表,该列表包含 Excel 中的所有数据 。
接下来我们就可以按照我们的需求处理我们的数据了,如果想把操作后的数据写回 Excel,也是一样的逻辑 。
使用 UserModel
让我们看看如何使用 UserModel 读取 Excel 文件 。此处使用 POI 4.0.0 版本,首先引入 poi 和 poi-ooxml 依赖:
< dependency>
< groupId> org.apache.poi </ groupId>
< artifactId> poi </ artifactId>
< version> 4.0.0 </ version>
</ dependency>
< dependency>
< groupId> org.apache.poi </ groupId>
< artifactId> poi-ooxml </ artifactId>
< version> 4.0.0 </ version>
</ dependency>
我们要读取一个简单的 Sku 信息表,内容如下:
聊聊Excel解析:如何处理百万行EXCEL文件?

文章插图
如何将 UserModel 的信息转化为数据列表?
我们可以通过实现反射 + 注解的方式定义表头到数据的映射关系,帮助我们实现 UserModel 到数据对象的转换 。实现基本思路是:① 自定义注解,在注解中定义列号,用来标注实体类的每个属性对应在 Excel 表头的第几列 。② 在实体类定义中,根据表结构,为每个实体类的属性加上注解 。③ 通过反射,获取实体类的每个属性对应在 Excel 的列号,从而到相应的列中取得该属性的值 。
以下是简单的实现,首先准备自定义注解 ExcelCol,其中包含列号和表头:
importjava.lang.annotation.ElementType;
importjava.lang.annotation.Retention;
importjava.lang.annotation.RetentionPolicy;
importjava.lang.annotation.Target;
@ Target({ ElementType.FIELD})
@ Retention( RetentionPolicy. RUNTIME)
public @interface ExcelCol {
/**
* 当前列数
*/
intindexdefault0;
/**
* 当前列的表头名称
*/
Stringheaderdefault"";
}
接下来,根据 Sku 字段定义 Sku 对象,并添加注解,列号分别为 0,1,2,并指定表头名称:
importlombok.Data;
importorg.shy.xlsx. annotation.ExcelCol;
@Data
publicclassSku{
@ExcelCol(index = 0, header = "sku")
privateLongid;
@ExcelCol(index = 1, header = "名称")
privateString name;
@ExcelCol(index = 2, header = "价格")
privateDoubleprice;
}
然后,用反射获取表头的每一个 Field,并以列号为索引,存入 Map 中 。从 Excel 的第二行开始(第一行是表头),遍历后面的每一行,对每一行的每个属性,根据列号拿到对应 Cell 的值,并为数据对象赋值 。根据单元格中值类型的不同,如文本 / 数字等,进行不同的处理 。以下为了简化逻辑,只对表头出现的类型进行了处理,其他情况的处理逻辑类似 。全部代码如下:
importcom.alibaba.fastjson.JSON;
importorg.apache.commons.lang3.StringUtils;
importorg.apache.poi.ss.usermodel.*;
importorg.apache.poi.xssf.usermodel.XSSFWorkbook;
importorg.shy.domAIn.pojo.Sku;
importorg.shy.xlsx.annotation.ExcelCol;
importjava.io.FileInputStream;
importjava.lang.reflect.Field;
importjava.text.DecimalFormat;
importjava.util.ArrayList;
importjava.util.HashMap;
importjava.util.List;
importjava.util.Map;
publicclassMyUserModel{
publicstaticvoid main( String[] args) throwsException{
List< Sku> skus = parseSkus( "D:sunhaoyu8DocumentsFilesskus.xlsx");


推荐阅读