前几天接到一个需求,简单来说就是要先读取用户传入的excel表头,根据表头来确定具体的处理方案,最开始我是选择通过poi来读取的,后面发现当数据量比较大时poi就容易出现内存溢出,后面就想到了easyexcel,但是我的这种读取方式多少有点不优雅,如果有更优雅的方案的兄弟欢迎留言或评论!
poi读取excel表头:
/**
* poi读取表头 默认获取第一个Sheet和第一行,以,分隔
*/
public static String getHead(InputStream stream) throws IOException {
Workbook wkbook = WorkbookFactory.create(stream);
Sheet rs = wkbook.getSheetAt(0);
Row row = rs.getRow(0);
StringJoiner headJoiner = new StringJoiner(",");
for (int i = 0; i < row.getLastCellNum(); i++) {
Cell cell = row.getCell(i);
if (Objects.nonNull(cell) && StringUtils.isNotEmpty(cell.toString().trim())) {
headJoiner.add(cell.toString().trim());
}
}
return headJoiner.toString();
}
但是使用poi读取表头时数据量一多就容易出现内存溢出,所以找到了easyexcel的方式,easyexcel读取表头的话采用的是继承easyexcel的 AnalysisEventListener,监听excel的读取在读取excel过程中进行表头拼接,将拼接结果存入Thread Local并手动抛出异常,结束excel读取,捕获异常,从ThreadLocal中取出结果来实现,代码如下:
1、监听器
package com.ylops.common.utils.poi;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.ylops.common.utils.StringUtils;
import java.util.*;
public class ExcelService extends AnalysisEventListener<Object> {
public static final ThreadLocal<String> RESP = new ThreadLocal<>();
@Override
public void invoke(Object data, AnalysisContext context) {
}
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
Set<Map.Entry<Integer, String>> entrySet = headMap.entrySet();
StringJoiner headJoiner = new StringJoiner(",");
for (Map.Entry<Integer, String> entry : entrySet) {
String value = entry.getValue();
if (StringUtils.isNotEmpty(value)) {
headJoiner.add(value);
}
}
//将表头存入ThreadLocal
RESP.set(headJoiner.toString());
//制造异常
int i = 1 / 0;
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
}
}
2、读取表头实现:
/**
* easyExcel读取表头,这里默认读取第一行作为表头,有需要的兄弟可以按需更改
*/
public static String readExcelHeadStr(InputStream is) {
try {
EasyExcel.read(is,
new ExcelService()).sheet().headRowNumber(1).doRead();
} catch (Exception e) {
}
String head = ExcelService.RESP.get();
// 释放ThreadLocal中存储的表头
ExcelService.RESP.remove();
return head;
}
到这里表头简单读取就结束了,有问题欢迎大佬指出!