easyexcel读取任意表格以及使用中的坑
easyexcel
快速、简洁、解决大文件内存溢出的java处理Excel工具
项目地址:https://gitcode.com/gh_mirrors/ea/easyexcel
免费下载资源
·
关于easyexcel通过模板读取表格的,网上已经有好多了,而且源码里也有详细的demo,这里就不在多说。这里记录一下我的使用。
一:
目前有个接口是上传Excel并且返回第一行,之前用的是POI,但是数据量大的话,100w条数据就oom了,所以切换到easyexcel,之后内存占用果然小了许多。
二:
首先引入依赖,目前我用的是2.1.4
<!-- 快速处理Excel工具-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.1.4</version>
</dependency>
然后创建一个listener,这个需要继承AnalysisEventListener,
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.ehl.etl.ext.utils.JSONArray;
import com.ehl.etl.ext.utils.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
public class ExcelReadListener extends AnalysisEventListener<Map<Integer, String>> {
private Logger logger = LoggerFactory.getLogger(ExcelReadListener.class);
// // 每隔N条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
private static final int BATCH_COUNT = 3000;
// 自定义用于暂时存储数据,通过Getter在方法中获取
JSONArray array = new JSONArray();
/**
* 在转换异常 获取其他异常下会调用本接口。抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行。
* 如果不重写该方法,默认抛出异常,停止读取
*
* @param exception
* @param context
* @throws Exception
*/
@Override
public void onException(Exception exception, AnalysisContext context) {
logger.error("解析失败,但是继续解析下一行:{}", exception.getMessage());
if (exception instanceof ExcelDataConvertException) {
ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception;
logger.error("第{}行,第{}列解析异常,数据为:{}", excelDataConvertException.getRowIndex(),
excelDataConvertException.getColumnIndex(), excelDataConvertException.getCellData());
}
}
/**
* 每解析一行会回调invoke()方法。
* 如果当前行无数据,该方法不会执行,
* 也就是说如果导入的的excel表无数据,该方法不会执行,
* 不需要对上传的Excel表进行数据非空判断
*
* @param map 当前读取到的行数据
* @param analysisContext 定义了获取读取excel相关属性的方法
*/
@Override
public void invoke(Map<Integer, String> map, AnalysisContext analysisContext) {
// 目前只需要表格第一行,这里直接跳过
return;
}
/**
* 这里会一行行的返回头,每个sheet只返回一次
*
* @param headMap
* @param context
*/
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
logger.info("解析到一条头数据:{}", headMap.toString());
for (int i = 0; i < headMap.size(); i++) {
JSONObject object = new JSONObject();
object.put("name","c_"+(i+1));
object.put("type","String");
if (headMap.get(i) == null) {
object.put("desc","");
} else {
object.put("desc",headMap.get(i));
}
array.add(object);
}
}
/**
* 解析监听器
* 每个sheet解析结束会执行该方法
*/
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
logger.info("/*------- 当前sheet读取完毕-------*/");
// 如果要在方法中拿到值,这里就不能清除,
// array.clear();
}
public JSONArray getArray() {
return array;
}
public void setArray(JSONArray array) {
this.array = array;
}
}
然后就是我们的主类了
InputStream inputStream = file.getInputStream();
BufferedInputStream bufferedInputStream = new BufferedInputStream(file.getInputStream());
ExcelReadListener listener = new ExcelReadListener();
ExcelReader excelReader = EasyExcelFactory.read(inputStream, listener).build();
// 直接读取第一个sheet,从0开始
ReadSheet readSheet = EasyExcel.readSheet(0).build();
excelReader.read(readSheet);
// 可以通过getter获取到listener中暂存的值,
JSONArray data = listener.getArray();
// 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的
excelReader.finish();
这样就不需要建立模板直接获取内容了。
有一点要注意:
这里默认是1,就是0行为头,从第一行开始读取内容,如果将这里指定为0的话,invokeHeadMap就拿不到值了。
三:
执行顺序是先执行invokeHeadMap然后是invoke遍历每一行,最后执行doAfterAllAnalysed结束,这里特别注意,如果在doAfterAllAnalysed中清除了暂存的值,那么在主函数中是拿不到的。
四:
如果在使用easyexcel时遇到这种问题,就是和POI的依赖冲突了。目前所知的2.1.4版本无法和3.14的POI一起存在,3.17版POI则没有冲突
关于这个工具我只是大概了解了一下,这个invoke方法如果有值的话每行都会调用它,那么如果我想只获取一行,但是数据量又特别大的时候,就会调用好多次invoke,造成效率低下。如果有人有好的方法欢迎留言。
GitHub 加速计划 / ea / easyexcel
31.64 K
7.47 K
下载
快速、简洁、解决大文件内存溢出的java处理Excel工具
最近提交(Master分支:3 个月前 )
c42183df
Bugfix 3 个月前
efa7dff6 * 重新加回 `commons-io`
3 个月前
更多推荐
已为社区贡献2条内容
所有评论(0)