重大推荐:读取导入的表格数据,请使用EasyExcal替代poi

13 篇文章 0 订阅
6 篇文章 0 订阅

为什么会是重大推荐呢?是因为公司线上出现了OOM!!!!
细思极恐
为啥呢?是因为我们在做导入的时候经常会面临两个问题
1、我们导入模版一般只是读取表格的第一个sheet,但是第一个sheet数据不多,但是导入的表格可能会非常大。
这有可能是因为存在其他的sheet,毕竟用户方我们控制不了。
2、虽然导入只有一个sheet,且数据看起来很少,但是代码读取却消耗了很大内存
这有可能是因为sheet数据的下面看起来是空的地方,存在大量的空格、有格式的空数据等。

目前发现的我们系统就是因为这两个问题,直接导致系统OOM。
重点分析报错之后,得出来一个结论:

划重点:读取excel的opi的方法大量消耗内存!!!

我们采用EasyExcal替换poi的读取方法
github源码如下:https://github.com/alibaba/easyexcel

EasyExcal详细的不再赘述,可以看源码,上面有很多的测试方法实例。

相关内存分析:https://blog.csdn.net/qq_34129814/article/details/118121974

EasyExcal和poi读取表格数据-简单的内存分析

代码取自项目里面的test方法,所以EasyExcal结合自己的系统的还是请看源码

public class EasyExcelUtil {
    private static Logger logger = LoggerFactory.getLogger(EasyExcelUtil.class);
	
	//这里本人方法是从文件服务器上的文件下载并读成了byte
	public static void getDataList(byte[] bytes){
	        try {
	//                    File file = new File("/Users/sunminghao/Downloads/过滤器.xlsx");
	//            List<Object> list = EasyExcel.read(file).sheet().headRowNumber(0).doReadSync();
	            
	            InputStream inputStream = new ByteArrayInputStream(bytes);
	            
	            //使用easyExcal直接读取sheet数据为一个list,其中包含的有标题信息
	            List<Object> list = EasyExcel.read(inputStream).sheet().headRowNumber(0).doReadSync();
	            logger.info("数据:{}", list.size());
	            logger.info("easyExcal 读取list 占用内存大小 = " + ObjectSizeCalculator.getObjectSize(list));
	
				//搞个测试方法(poi读取表格数据)
	            poiTest(bytes);

				//因为老代码是poi的sheet做的,为了尽可能的少改代码,顺便测一下转sheet
	            getSheetByList(list);
	
	        }catch (Exception e){
	            logger.error("EasyExcelUtil getDataList is error", e);
	        }
	    }


    public static void poiTest(byte[] bytes) throws IOException, InvalidFormatException {
        Workbook workbook = WorkbookFactory.create(new ByteArrayInputStream(bytes));
        Sheet sheet = workbook.getSheetAt(0);
        logger.info("poi sheet getLastRowNum = " + sheet.getLastRowNum());

        logger.info("poi sheet workbook 占用内存大小 = " + ObjectSizeCalculator.getObjectSize(workbook));
        logger.info("poi sheet sheet 占用内存大小 = " + ObjectSizeCalculator.getObjectSize(sheet));

    }


    public static void getSheetByList(List<Object> list){
        HSSFWorkbook workbook = new HSSFWorkbook();
        HSSFSheet sheet = workbook.createSheet("用户信息");

        if(list != null && list.size()>0) {
            Object firstObject = list.get(0);
            HSSFRow head = sheet.createRow(0);
            String str1= JSONObject.toJSON(firstObject).toString();
            HashMap hashMap1 = JSON.parseObject(str1, HashMap.class);
            for (int i=0;i<hashMap1.size();i++){
                head.createCell(i).setCellValue(hashMap1.get(String.valueOf(i)).toString());
            }
            list.remove(0);
            for (Object object : list) {
                HSSFRow body = sheet.createRow(sheet.getLastRowNum()+1);
                String str= JSONObject.toJSON(object).toString();
                HashMap hashMap = JSON.parseObject(str, HashMap.class);
                for (int i=0;i<hashMap.size();i++){
                    body.createCell(i).setCellValue(hashMap.get(String.valueOf(i)) == null ? "" : hashMap.get(String.valueOf(i)).toString());
                }
            }
        }
        logger.info("将easyExcal读取的list转成poi的sheet  占用内存大小 = " + ObjectSizeCalculator.getObjectSize(sheet));

    }
}

运行结果:(被整理过,截图不太好 哈哈哈)

数据:920 
easyExcal 读取list 占用内存大小 = 620520 

poi sheet getLastRowNum = 919 
poi sheet workbook 占用内存大小 = 69408488 
poi sheet sheet 占用内存大小 = 69450176 

将easyExcal读取的list转成poi的sheet  占用内存大小 =  1222856 

结果很明显嘛

1、easyExcal搞出来的数据占用的内存很小嘛(毕竟我们主要取第一个sheet)

详细的可以看方法源码,poi的读取方法里面进行的大量的对象转换赋值判断等等,使内存消耗非常的大。而easyExcal则是大刀阔斧的处理。

2、我们再将list转化成为sheet的时候,其实内存直接就进行了翻倍

这里我们是人工处理,当然easyExcal里面也有poi的sheet处理,但是都是不推荐使用的,这里我们手写一个简单的更直观

遗留问题!!

为什么我们读取到的workbook对象占用内存 竟然和 sheet内存差不多!
甚至还有多个sheet的workbook内存竟然还没有一个sheet的内存大?????

Why?

有待下次分析

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java程序源

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值