【Alibaba工具型技术系列】「EasyExcel技术专题」实战研究一下 EasyExcel 如何从指定文件位置进行读取数据

实战研究一下 EasyExcel 如何从指定文件位置进行读取数据

      • EasyExcel的使用背景
      • EasyExcel的时候痛点
        • EasyExcel对比其他框架
      • EasyExcel的编程模式
        • EasyExcel读取的指定位置
        • 导入数据的流程
          • 表头校验
            • invokeHeadMap()方法
          • 数据处理
            • invoke()方法
          • 执行中断
            • hasNextdoAfterAllAnalysed()方法
          • 数据完成
            • doAfterAllAnalysed()方法
  • 总结一下

EasyExcel的使用背景

工作中总会遇到对Excel读写功能,之前接触过EasyExcel,后续我们基本上用它代替了传统的POI和JXL、甚至还有一个EasyPOI技术。

EasyExcel的时候痛点

使用的EasyExcel时候,一般场景下表头比较传统,也不复杂,但是这次呢表头稍微有点复杂,读取数据要从指定的位置开始,要从指定位置开始读取EasyExcel,所以呢在不断的摸索之后,找到了合适的解决方法。

EasyExcel对比其他框架

平常用poi读取excel数据量少,加上EasyExcel读取Excel有点复杂,所以一直也没在项目中使用EasyExcel,直到有一回要读取的数据量太大,使用poi读取Excel在创建Workbook -> WorkbookFactory.create(inputStream) 时就异常了,分配很多内存也不好使,所以放弃使用poi转使用EasyExcel。

Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到几M,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。

在上层做了模型转换的封装,让使用者更加简单方便 --EasyExcel
使用EasyExcel读取Excel时一直在想如何简化读取方式,不用读取每个Excel都创建一个XXDataListene监听器类,刚开始想,把DataListener加上泛型,共用一个DataListener,但是还涉及到如何传递Dao和每个Dao如何保存数据,而且保存数据前可能还需要对数据进行不同的处理。

EasyExcel的编程模式

EasyExcel开源挺久了,但使用上感觉有点让人望而生怯,刚开始看官方文档上读取Excel挺简单的,只需要一行代码,继续细看的话还需要创建一个回调监听器,有点复杂呀(每个Excel都需要创建一个单独的回调监听器类)。

EasyExcel读取的指定位置

要开始读取数据,第8行才是真正的数据,直接上代码,headRowNumber(),不写默认是1,即就是从第二行开始读数据。

    /*** 读取文件信息数据* @param filePath* @param headNum*/public ContactInfoExcelDataListener read(String filePath , int headNum){EasyExcel.read(filePath, this).head(ContactInfoExcelEntity.class).autoCloseStream(true).autoTrim(true).ignoreEmptyRow(true).sheet()// 这里可以设置1,因为头就是一行。如果多行头,可以设置其他值。不传入也可以,因为默认会根据DemoData 来解析,他没有指定头,也就是默认1行.headRowNumber(Math.max(headNum,NumberUtils.BYTE_ZERO)).doRead();return this;}/*** 读取文件信息数据* @param filePath*/public ContactInfoExcelDataListener read(String filePath){EasyExcel.read(filePath, this).head(ContactInfoExcelEntity.class).autoCloseStream(true).autoTrim(true).ignoreEmptyRow(true).sheet()// 这里可以设置1,因为头就是一行。如果多行头,可以设置其他值。不传入也可以,因为默认会根据DemoData 来解析,他没有指定头,也就是默认1行.doRead();return this;}/*** 读取文件信息数据* @param inputStream* @param headNum*/public ContactInfoExcelDataListener read(InputStream inputStream, int headNum){EasyExcel.read(inputStream, this).head(ContactInfoExcelEntity.class).autoCloseStream(true).autoTrim(true).ignoreEmptyRow(true).sheet()// 这里可以设置1,因为头就是一行。如果多行头,可以设置其他值。不传入也可以,因为默认会根据DemoData 来解析,他没有指定头,也就是默认1行.headRowNumber(Math.max(headNum,NumberUtils.BYTE_ZERO)).doRead();return this;}
导入数据的流程

基本都会走到这里,全部放权交接给invoke方法,并且巧用作为我们锁初始化操作的控制赋值,切记如果headNum = 0 此方法很有可能不会触发,慎用!

表头校验

目前只是实现了相关的单节点同步锁,如果未来扩展了相关的分布式节点,需要采用分布式锁机制进行控制!锁范围需要进行控制

invokeHeadMap()方法
/*** 调用头部* @param map* @param analysisContext*/@Overridepublic void invokeHead(Map<Integer, CellData> map, AnalysisContext analysisContext) {log.info("【start read the excel head data】:{}",map);// 判断标记头是否存在try {int titleRows = map.size();// 头部的中断处理机制!failureDataCount = preValidate?orginalHead.size() != titleRows?NumberUtils.INTEGER_ONE:NumberUtils.BYTE_ZERO:NumberUtils.BYTE_ZERO;// 进行置位if(preValidate && (failureDataCount.intValue() == NumberUtils.INTEGER_ONE)){causeByHeadFormatAbort = Boolean.TRUE;}if(!isMockFlag) {// TODO 基本不会走到这里:一般我们如果需要可以使用此方法作为初始化资源使用的目的!//Preconditions.checkNotNull(clueLogic,"not support clueLogic is inject this class subject!");if (Objects.isNull(clueLogic)) {clueLogic = SpringUtils.getBean(ClueLogic.class);}customerImportVO = new CustomerImportVO();// 此部分主要是为了减少不必要的内存空间的申请tempDataList = Lists.newArrayListWithExpectedSize(batchSizeUnit);}
//            syncLockController.lock();} catch (Exception e) {log.error("invoke the analysis the title head info data is failure!",e);throw new UnsupportedOperationException("invoke the analysis the title head info data is failure!",e);}log.info("【finished read the excel head data】");}
数据处理
invoke()方法

一条一条数据解析 invoke()方法 ,方法里面是我业务逻辑,数据校验。invoke 就是每行具体的数据值

    /*** 调用操作处理控制机制* @param excelEntity* @param context*/@Overridepublic void invoke(ContactInfoExcelEntity excelEntity, AnalysisContext context) {log.info("----【start read the excel main data:{}】----",excelEntity);if(batchSizeUnit <= tempDataList.size()){CustomerImportVO customerImportVO = clueLogic.startCallTaskProxy(contactInfoImportParam,tempDataList);// 合并计算结果->更新为最新的结果this.customerImportVO.merge(customerImportVO);tempDataList.clear();tempDataList = Lists.newArrayListWithExpectedSize(batchSizeUnit);}else{tempDataList.add(excelEntity);}log.info("【finished read the excel main data】");}
执行中断
hasNextdoAfterAllAnalysed()方法
    /*** 是否拥有下一次执行* [@param](https://my.oschina.net/u/2303379) context* [@return](https://my.oschina.net/u/556800)*/[@Override](https://my.oschina.net/u/1162528)public boolean hasNext(AnalysisContext context) {return causeByHeadFormatAbort?Boolean.FALSE:isSupportAbort? failureDataCount <= 0 :Boolean.TRUE;}
数据完成
doAfterAllAnalysed()方法

所有数据解析完, doAfterAllAnalysed()方法,里面写的有保存数据方法。

    /*** 执行结束的回调机制* @param analysisContext*/@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {log.info("【doAfterAllAnalysed the process】");try {CustomerImportVO customerImportVO = clueLogic.startCallTaskProxy(contactInfoImportParam,tempDataList);this.customerImportVO.merge(customerImportVO);finisheDataResult = Boolean.TRUE;}catch (Exception e){log.error("execute finially the flush data is failure!");//TODO 收尾的数据信息如何做到一致性和完成补偿!finisheDataResult =  Boolean.FALSE;} finally {tempDataList.clear();
//            syncLockController.unlock();}}

总结一下

  • 快速读写:EasyExcel 支持 Excel 2003 和 Excel 2007 格式,并提供高效的读写性能。它使用了 NIO(新输入/输出)技术,使得读写操作更加快速。
  • 简单易用:EasyExcel 的 API 设计简洁明了,易于使用。开发者只需编写少量代码,即可完成 Excel 文件的读写操作。它还支持链式编程,使代码更加简洁。
  • 支持自定义:EasyExcel 提供了丰富的自定义选项,允许开发者根据需要调整 Excel 文件的格式、样式等。它还支持自定义公式、条件格式等功能,满足各种业务需求。
  • 灵活的配置:EasyExcel 支持多种配置方式,如属性配置、注解配置等。开发者可以根据项目需求选择合适的配置方式,使得 Excel 文件的处理更加灵活。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/638574.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

打折:阿里云国外服务器价格购买优惠活动

阿里云国外服务器优惠活动「全球云服务器精选特惠」&#xff0c;国外服务器租用价格24元一个月起&#xff0c;免备案适合搭建网站&#xff0c;部署独立站等业务场景&#xff0c;阿里云服务器网aliyunfuwuqi.com分享阿里云国外服务器优惠活动&#xff1a; 全球云服务器精选特惠…

idea 折叠某段代码 这段特定某段代码

如何折叠IntelliJ IDEA代码片段_w3cschool ctrlALTT

圆的参数方程是如何推导的?

圆的参数方程是如何推导的? 1. 圆的三种参数表示2. 三角函数万能公式3. 回到圆的参数方程1. 圆的三种参数表示 已知圆的第一种参数方程为: x 2 + y 2 = r x^2+y^2=r x2+y2=r   圆的图像如下: 通过上图,不难理解,圆的参数方程还可以用三角函数表示,也就是第二种参数表…

计算机毕业设计 | SpringBoot学生成绩管理系统(附源码)

1&#xff0c; 概述 1.1 课题背景 开发一个学生成绩管理系统&#xff0c;采用计算机对学生成绩进行处理&#xff0c;进一步提高了办学效益和现代化水平。为广大教师和学生提高工作效率&#xff0c;实现学生成绩信息管理工作流程的系统化、规范化和自动化。现在我国中学的学生…

基于STM32CubeMX创建FreeRTOS—以STM32F429为例

目录 1. 实验任务 2. 使用STM32CubeMX创建基础工程 2.1 打开STM32CubeMX 2.2 创建新项目 2.3 时钟设置 2.5 修改时钟基准&#xff0c;打开串行调试 2.6 配置串口 2.7 配置状态指示灯 2.8 FreeRTOS 2.9 配置工程输出项 3. 代码编辑 3.1 printf重映射 3.1.1 使用ARM…

【JavaEE】网络初识 (IP地址, 端口号, 协议, 封装和分用)

文章目录 前言网络通信基础一.IP地址概念格式特殊IP 二.端口号概念注意事项 三.协议概念知名协议的默认端口五元组协议分层OSI七层模型TCP/IP五层模型 四.封装和分用 前言 本章来介绍一下网络中的一些基本概念, 例如 : IP地址, 端口号, 协议, 协议分层, 封装, 分用等等. 网络…

计组原理:系统概论与基本组成

系统概论与基本组成 系统概论硬件软件 计算机系统的层次结构系统复杂性的管理方法1&#xff1a;抽象 计算机的基本组成冯诺依曼计算机系统复杂性的管理方法 2&#xff1a;&#xff08;3’Y&#xff09; 计算机的工作步骤上机前的准备&#xff1a;计算机的解题过程存储器的基本组…

2024.1.21力扣每日一题——分割数组的最大值

2024.1.21 题目来源我的题解方法一 动态规划前缀和方法二 贪心二分方法三 贪心二分&#xff08;自己的&#xff09; 题目来源 力扣每日一题&#xff1b;题序&#xff1a;410 我的题解 方法一 动态规划前缀和 参考官方题解 令 dp[i][j]表示将数组的前 i 个数分割为 j段所能得…

AI教我学编程之C#类的实例化与访问修饰符

前言 在这篇文章中&#xff0c;我将带大家深入了解C#编程语言的核心概念&#xff0c;包括类的实例化、访问修饰符的应用&#xff0c;以及C#中不同数据类型的默认值。我会通过逐步分析和具体实例&#xff0c;详细解释如何在C#中正确创建和操作对象&#xff0c;并探讨如何通过访…

chatgpt和文心一言哪个更好用?更智能?

我来分别对CHATGPT和文心一言在智能回复、语言准确性和知识库丰富度等方面进行描述和对比。 智能回复&#xff1a; CHATGPT&#xff1a;由于是基于OpenAI的大模型训练而成&#xff0c;CHATGPT具备强大的智能回复能力。它可以理解上下文、推理和表达观点&#xff0c;能够提供准…

维基百科推广的12种方法帮你建立强大的品牌-华媒舍

维基百科是全球最大、最权威的多语言网络百科全书。它是许多人搜索信息、获取知识的首选平台&#xff0c;也是许多品牌建立强大影响力的重要途径。本文将介绍维基百科推广的12种方法&#xff0c;帮助你在维基百科上建立强大的品牌形象。 1. 准备工作 在开始维基百科推广之前&a…

IDEA怎么用Devtools热部署

IDEA怎么用Devtools热部署 大家知道在项目开发过程中&#xff0c;有时候会改动代码逻辑或者修改数据结构&#xff0c;为了能使改动的代码生效&#xff0c;往往需要重启应用查看改变效果&#xff0c;这样会相当耗费时间。 重启应用其实就是重新编译生成新的Class文件&#xff0…

机器学习:何为监督学习和无监督学习

目录 一、监督学习 &#xff08;一&#xff09;回归 &#xff08;二&#xff09;分类 二、无监督学习 聚类 一、监督学习 介绍&#xff1a;监督学习是指学习输入到输出&#xff08;x->y&#xff09;映射的机器学习算法&#xff0c;监督即理解为&#xff1a;已知正确答案…

C语言总结十一:自定义类型:结构体、枚举、联合(共用体)

本篇博客详细介绍C语言最后的三种自定义类型&#xff0c;它们分别有着各自的特点和应用场景&#xff0c;重点在于理解这三种自定义类型的声明方式和使用&#xff0c;以及各自的特点&#xff0c;最后重点掌握该章节常考的考点&#xff0c;如&#xff1a;结构体内存对齐问题&…

C++PythonC# 三语言OpenCV从零开发(5):ROI截取

文章目录 前言ROI测试图片部分区域截取CCsharpPython 颜色区域分割CCsharpPython 颜色通道合并CCsharpPython 总结 前言 C&Python&Csharp in OpenCV 专栏 【2022B站最好的OpenCV课程推荐】OpenCV从入门到实战 全套课程&#xff08;附带课程课件资料课件笔记&#xff09…

Mybatis Plus baomidou EasyCode插件自动生成驼峰字段实体类,而不是全小写字段实体类

开发环境&#xff1a; springboot 2.4.3baomidou 3.4.0mybatis plus 3.4.0jdk8 问题描述&#xff1a; 1、mybatis 使用baomidou 插件&#xff0c;EasyCode自动生成实体类&#xff0c;但字段都是全部小写的&#xff0c;不太符合编码规范。 2、mysql表字段全是驼峰&#xff0c…

java基础05-int 和 Integer 有什么区别?

int 和 Integer 有什么区别&#xff1f; &#x1f339;&#x1f339;&#x1f339;&#x1f339;&#x1f339;&#x1f339;&#x1f339;&#x1f339;&#x1f339;&#x1f339;&#x1f339;&#x1f339;&#x1f339;&#x1f339;&#x1f339;&#x1f339;&#x1f…

大数据技术原理及应用课实验3 :熟悉常用的HBase操作

目录 实验3 熟悉常用的HBase操作 一、实验目的 二、实验平台 三、实验步骤&#xff08;每个步骤下均需有运行截图&#xff09; &#xff08;一&#xff09;编程实现以下指定功能&#xff0c;并用Hadoop提供的HBase Shell命令完成相同任务&#xff1a; 1.列出HBase所有的表…

代码随想录算法训练营第五十二天| 300.最长递增子序列、674.最长连续递增序列、718.最长重复子数组

代码随想录算法训练营第五十二天| 300.最长递增子序列、674.最长连续递增序列、718.最长重复子数组 题目 300.最长递增子序列 给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&…

科大讯飞将于1月30日发布星火大模型 V3.5,基于全国产化算力底座训练

科大讯飞即将发布全新AI大模型——星火认知大模型 V3.5&#xff0c;该模型将于14:00正式发布。据透露&#xff0c;相比于去年10月24日发布的V3.0版本&#xff0c;V3.5在逻辑推理、文本生成、数学答题及小样本学习能力上均实现了显著提升。 科大讯飞官网链接&#xff1a;讯飞星…