深入解析 EasyExcel 组件原理与应用

深入解析 EasyExcel 组件原理与应用

官方:EasyExcel官方文档 - 基于Java的Excel处理工具 | Easy Excel 官网

在日常的 Java 开发工作中,处理 Excel 文件的导入导出是极为常见的需求。
今天,咱们就一起来深入了解一款非常实用的操作 Excel 的组件 ——EasyExcel,看看它究竟有着怎样的神奇之处,能让众多开发者青睐有加。

一、引言

想必大家都知道,在 Java 领域中,Apache POI 是处理 Excel 文件的老牌工具了。但随着业务发展,面对越来越大的 Excel 文件读写需求时,POI 暴露出了一些诸如内存溢出(OOM)等问题,使用起来稍显吃力。而 EasyExcel 的出现,很好地弥补了这些不足,它基于 POI 进行了优化封装,为我们提供了更加简洁高效的 Excel 处理方式。接下来,咱们就详细剖析一下 EasyExcel 的原理以及它的具体应用。

二、EasyExcel 与 Apache POI 的渊源

EasyExcel 其实是站在 Apache POI 这个 “巨人的肩膀” 上发展起来的。Apache POI 基于 OOXML(Office Open XML)标准(像 xlsx、docx、pptx 等以指定格式的 xml 为基础并以 zip 格式压缩的文件)和 OLE2 标准(包括 xls、doc、ppt 等二进制格式的文件),只要符合上述标准的文件它都能进行读写操作。

对于 xlsx 文件来说,它基于 OOXML 标准,能够解压成对应的 xml 文件,在解析后的 xml 文件里,我们重点关注 sharedStrings.xml 与 sheet1.xml 这两个 xml 节点,因为里面存放着我们想要处理的 Excel 内容。

不过,POI 在处理 Excel 时有传统的 POM 解析和 SAX 解析两种方式。传统的 POM 解析会把 Excel 中的所有 XML 节点解析成一棵 DOM 树,整棵 DOM 树加载进内存,这样做虽然方便对每个 XML 节点进行随机访问,但很容易导致内存溢出现象,像仅仅 3 列的 Excel 文件在 7 万行左右就可能出现内存溢出问题。

而 SAX 解析则不同,它采用边读取边处理的方式操作 XML,逐行扫描 XML 文档,遇到标签时触发解析处理器,进而触发相应的事件 Handler。这种方式内存占用小、效率高,但 POI 官方提供的 API 过于繁琐,使用起来步骤繁多,比如读取一个 Excel 文件,要先将 xlsx 格式的 Excel 文件解析成 OPCPackage 对象,再创建 XSSFReader 对象来解析获取对应 xlsx 下的 xml 内容,想要处理还得进一步创建内容处理器等等,着实有些麻烦。

三、EasyExcel 的原理剖析

(一)核心架构与流程

在 EasyExcel 中,有一个核心的类叫 ExcelAnalyserImpl,它就像是整个操作的调度中心。里面包含了 AnalysisContext 类(分析上下文,存放对应的文件 Inputstream 跟 AnalysisEventListener 事件监听处理器等)和 ExcelReadExecutor 类(默认是 XlsxSaxAnalyser 类,核心方法是 parseXmlSource (),负责逐行 SAX 解析 Excel)。

当 XlsxSaxAnalyser 解析类执行解析方法后,会调用 AnalysisEventProcessor 执行对应的事件方法,而在这个 processor 里真正执行操作的就是对应的事件监听器啦。官方默认提供了一个事件监听器,能把 Excel 解析成 BeanMap 的形式,然后根据我们传入的实体类,返回给我们想要的实体类对象。要是我们有定制化的功能需求,那就需要去了解这个监听器的核心方法了哦。

以下是一个简单的示例代码,展示如何使用 EasyExcel 读取 Excel 文件并将数据转换为自定义对象(假设我们有一个 User 实体类,包含 name 和 age 等属性):

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;// 自定义监听器,用于处理读取到的数据
class UserDataListener extends AnalysisEventListener<User> {private List<User> userList = new ArrayList<>();// 每解析一行数据就会调用此方法@Overridepublic void invoke(User user, AnalysisContext analysisContext) {userList.add(user);}// 全部解析完成后调用此方法@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {// 这里可以对读取到的所有数据进行后续操作,比如存入数据库等System.out.println("共读取到 " + userList.size() + " 条用户数据");}public List<User> getUserList() {return userList;}
}public class EasyExcelReadExample {public static void main(String[] args) throws IOException {String filePath = "your_excel_file_path.xlsx";  // 替换为实际的 Excel 文件路径// 读取 Excel 文件,第二个参数是自定义的监听器EasyExcel.read(new FileInputStream(filePath), User.class, new UserDataListener()).sheet().doRead();}
}
注解

  • 在上述代码中,首先定义了 UserDataListener 类,它继承自 AnalysisEventListener,并重写了 invoke 和 doAfterAllAnalysed 方法。invoke 方法用于在每解析一行 Excel 数据时将其封装成 User 对象并添加到 userList 中,而 doAfterAllAnalysed 方法则在整个 Excel 文件解析完成后执行,可以在这里进行一些后续的数据处理操作,比如将数据批量存入数据库等。
  • 在 EasyExcelReadExample 类的 main 方法中,通过 EasyExcel.read 方法来启动 Excel 文件的读取流程,传入文件输入流、要转换的目标对象类型(这里是 User 类)以及自定义的监听器,然后调用 sheet 和 doRead 方法完成读取操作。

(二)关键方法解析

1. doRead () 方法
doRead () 方法实际调用过程还挺有意思的,它先是调用了 ExcelReader 中的 read 方法与 finish 方法。read 方法实际调用了 Executor 中的 execute 方法,这个 execute 方法里会调用前面提到的核心方法 parseXmlSource 解析 excel,并且在一个 sheet 中所有数据读取完后,会调用事件调度器的 endSheet 方法,让每一个监听器执行对应的 doAfterAllAnalysed 方法。而 finish 方法则负责对读取过程持有容器中流的内容输出,之后清理存储的缓存,把开启的相应的流关闭。
2. doWrite () 方法
doWrite () 方法同样调用了 Writer 中的 write 方法和 finish 方法,这里的 finish 方法作用和读操作里类似哦。write 方法实际调用的是 Builder 中的 addContent 方法,在 addContent 方法里又会调用 Executor 中的 add 方法,针对传入的列表,逐个对象执行 addOneRowOfDataToExcel 方法进行逐行写入。在这个过程中,无论是创建行对象前后,还是填充完数据之后,我们都可以自定义处理器对流程进行相应的处理呢,非常灵活。

以下是一个使用 EasyExcel 写入 Excel 文件的示例代码,假设我们要将一个 List<User> 数据写入到 Excel 中:

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.write.metadata.WriteSheet;
import java.util.ArrayList;
import java.util.List;class User {private String name;private int age;// 构造函数、Getter 和 Setter 方法省略,可根据实际情况补充完整public User(String name, int age) {this.name = name;this.age = age;}
}public class EasyExcelWriteExample {public static void main(String[] args) {List<User> userList = new ArrayList<>();userList.add(new User("张三", 25));userList.add(new User("李四", 30));String filePath = "output_excel_file.xlsx";  // 输出的 Excel 文件路径// 这里使用 EasyExcel 的 write 方法开始写入操作EasyExcel.write(filePath, User.class).sheet("用户信息表").doWrite(userList);}
}
注解

  • 在这个示例中,先定义了 User 类来表示要写入 Excel 的数据对象,包含 name 和 age 等属性(这里省略了部分常规的方法,实际使用中需补充完整)。
  • 在 EasyExcelWriteExample 类的 main 方法中,创建了一个 List<User> 集合并添加了一些示例数据。然后通过 EasyExcel.write 方法启动写入流程,传入输出文件路径和要写入的数据对象类型(User 类),接着指定 sheet 名称,最后调用 doWrite 方法并传入数据列表,这样就可以将数据成功写入到指定的 Excel 文件中啦。

四、EasyExcel 的性能与易用性优势

(一)性能优势

通过官方给出的效果图可以看到,EasyExcel 仅用 16M 内存在 23 秒内就能读取 75M(46W 行 25 列)的 Excel 文件,相比之下,POI 读取内存要用到 100M 往上了,读取时间更是没法比,可见在性能方面,EasyExcel 是遥遥领先呀。这得益于它基于事件机制逐行扫描数据,对数据逐行处理后,只要对象不被引用,就会被 JVM 快速垃圾回收,从而有效避免了 OOM 问题。

(二)易用性优势

使用 EasyExcel 进行文件的导入导出,相比 POI 的流程那可是简化了一大截呢,只要短短几行代码就可以轻松实现 Excel 的导入导出。这对于咱们开发者来说,简直太友好了,能大大提高开发效率呀。

五、EasyExcel 中的设计模式 个人理解

(一)工厂模式

EasyExcel 里的 EasyExcelFactory 类就运用了工厂模式哦。这个类拥有很多对应方法的不同入参的变体,最终目的都是为了根据不同的入参构造对应的 ExcelWriter/ReaderBuilder 对象,让代码调用起来简洁又美观呢。

(二)观察者模式(也叫发布 - 订阅模式)

通过事件监听器的机制,实现了类似观察者模式的效果。当 Excel 文件解析过程中遇到行、单元格等情况时会触发事件,然后通过自定义监听器来处理数据,各个监听器就像是观察者一样,等待着对应的事件发生然后执行相应的操作。

(三)模板方法模式

在解析和写入等流程中,定义了一些模板化的方法,不同的实现类可以按照这些模板去扩展和定制具体的业务逻辑,保证了整体流程的规范性和可扩展性。

(四)装饰器模式

在写样式等方面运用了装饰器模式,方便我们对 Excel 的样式等进行个性化的装饰和处理,让生成的 Excel 文件更加符合实际业务需求。

六、实际应用案例

在实际项目中,EasyExcel 发挥着巨大的作用呢。比如说,我曾经需要从 Excel 表格中批量导入用户信息到 MySQL 数据库里。如果使用 POI,不仅操作复杂,而且面对稍大一点的 Excel 文件就容易出现内存溢出问题。而选择 EasyExcel 后,它简单易用,性能又优越,更重要的是能够节约内存、解决大文件内存溢出问题。像一个 3M 的 excel 文件,用 POI sax 解析依然需要 100M 左右内存,改用 easyexcel 后可以降低到几 M,而且再大的 excel 文件也不会出现内存溢出啦。对于数据量小的文件,我采用同步模式一次性获取所有表格数据并存储到 List 中;对于数据量大的文件,则采用自定义 Listener 的方式异步逐行读取 Excel 并分批插入到数据库中,非常方便高效。

七、总结

总的来说,EasyExcel 作为一款强大的 Excel 处理组件,在 Apache POI 的基础上进行了优化和封装,无论是在性能、易用性还是功能扩展性上都有着出色的表现。通过运用多种设计模式,让它更加灵活且易于使用,在实际项目中能够帮我们轻松应对各种 Excel 文件的读写需求,大大提高了开发效率,也减少了因为内存溢出等问题带来的烦恼。希望大家在之后的开发工作中,如果遇到 Excel 处理相关的业务,不妨试试 EasyExcel 哦,相信它会给你带来意想不到的惊喜。

以上就是本次关于 EasyExcel 的全部内容分享啦,大家如果有任何疑问或者使用心得,欢迎在评论区留言交流呀。

觉得有用的话可以点点赞 (*/ω\*),支持一下。

如果愿意的话关注一下。会对你有更多的帮助。

每天都会不定时更新哦  >人<  。

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

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

相关文章

Java爬虫:获取商品详情的实践之旅

在当今这个信息爆炸的时代&#xff0c;数据的价值日益凸显。对于电商行业来说&#xff0c;商品详情的获取尤为重要&#xff0c;它不仅关系到产品的销售&#xff0c;还直接影响到用户体验。传统的人工获取方式耗时耗力&#xff0c;而自动化的爬虫技术则提供了一种高效解决方案。…

C# 数据结构之【树】C#树

以二叉树为例进行演示。二叉树每个节点最多有两个子节点。 1. 新建二叉树节点模型 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks;namespace DataStructure {class TreeNode{public int Data { get;…

单片机_简单AI模型训练与部署__从0到0.9

IDE&#xff1a; CLion MCU&#xff1a; STM32F407VET6 一、导向 以求知为导向&#xff0c;从问题到寻求问题解决的方法&#xff0c;以兴趣驱动学习。 虽从0&#xff0c;但不到1&#xff0c;剩下的那一小步将由你迈出。本篇主要目的是体验完整的一次简单AI模型部署流程&#x…

【Spiffo】环境配置:VScode+Windows开发环境

摘要&#xff1a; 在Linux下直接开发有时候不习惯快捷键和操作逻辑&#xff0c;用Windows的话其插件和工具都更齐全、方便&#xff0c;所以配置一个Windows的开发环境能一定程度提升效率。 思路&#xff1a; 自己本地网络内远程连接自己的虚拟机&#xff08;假定用的是虚拟机…

使用eclipse构建SpringBoot项目

我这里用eclipse2018版本做演示&#xff0c;大家有需要的可以下载Eclipse Downloads | The Eclipse Foundation 1.打开eclipse&#xff0c;选择存放代码的位置 2.选择 file >> new >> project >> 选择springboot文件下的 spring starter project 2.这里选择N…

C++ 日期计算器的实现(运算符重载)

目录 一、前言 二、正文 1.1 Date类框架 1.2 两个日期间的直接赋值 1.3判断两个日期是否相同 1.4判断两个日期是否不同 1.5日期加天数 1.6日期天数 1.7日期的前置和后置 1.8日期减天数 1.9自身日期减天数 2.1自身日期前置--和后置-- 2.2两个日期的差值为差距天数 2…

LLM的原理理解6-10:6、前馈步骤7、使用向量运算进行前馈网络的推理8、注意力层和前馈层有不同的功能9、语言模型的训练方式10、GPT-3的惊人性能

目录 LLM的原理理解6-10: 6、前馈步骤 7、使用向量运算进行前馈网络的推理 8、注意力层和前馈层有不同的功能 注意力:特征提取 前馈层:数据库 9、语言模型的训练方式 10、GPT-3的惊人性能 一个原因是规模 大模型GPT-1。它使用了768维的词向量,共有12层,总共有1.…

如何使用 Python 开发一个简单的文本数据转换为 Excel 工具

目录 一、准备工作 二、理解文本数据格式 三、开发文本数据转换为Excel工具 读取CSV文件 将DataFrame写入Excel文件 处理其他格式的文本数据 读取纯文本文件: 读取TSV文件: 四、完整代码与工具封装 五、使用工具 六、总结 在数据分析和处理的日常工作中,我们经常…

太通透了,Android 流程分析 蓝牙enable流程(应用层/Framework/Service层)

零. 前言 由于Bluedroid的介绍文档有限&#xff0c;以及对Android的一些基本的知识需要了(Android 四大组件/AIDL/Framework/Binder机制/JNI/HIDL等)&#xff0c;加上需要掌握的语言包括Java/C/C等&#xff0c;加上网络上其实没有一个完整的介绍Bluedroid系列的文档&#xff0…

李继刚:提示词(Prompt)的本质是表达的艺术

看了李继刚在 AI 创新者大会的演讲《提示词的道与术》&#xff0c;收获很大&#xff0c;我分享一下学习笔记。  李继刚&#xff1a;提示词&#xff08;Prompt&#xff09;的本质是表达的艺术 一、提示词的本质是表达 本意、文意和解意的概念&#xff1a; 本意&#xff1a;指…

复古风格渐变褪色人像旅拍Lr调色教程,手机滤镜PS+Lightroom预设下载!

调色教程 这种调色风格旨在通过调整色彩和光影&#xff0c;为人像旅拍照片赋予复古的氛围和艺术感。渐变褪色效果增添了一种时光沉淀的感觉&#xff0c;使照片仿佛来自过去的岁月。 预设信息 调色风格&#xff1a;复古风格预设适合类型&#xff1a;人像&#xff0c;街拍&…

Android Studio更改项目使用的JDK

一、吐槽 过去&#xff0c;在安卓项目中配置JDK和Gradle的过程非常直观&#xff0c;只需要进入Android Studio的File菜单中的Project Structure即可进行设置&#xff0c;十分方便。 原本可以在这修改JDK: 但大家都知道&#xff0c;Android Studio的狗屎性能&#xff0c;再加…

字节青训营开课啦

系列文章目录 文章目录 系列文章目录一、字节青训营是什么&#xff1f;二、你将获得三、入营条件四、课程简介1.前端2.后端3.大数据 五、报名 一、字节青训营是什么&#xff1f; 青训营是字节跳动技术团队发起的技术系列培训&人才选拔项目&#xff1b;面向高校在校生&…

医药企业的终端市场营销策略

近年来&#xff0c;随着医药行业的快速发展&#xff0c;终端市场逐渐成为企业竞争的关键领域。在政策趋严、市场环境变化以及数字化转型的大背景下&#xff0c;医药企业如何在终端市场中立于不败之地&#xff1f;本文结合我们在医药数字化领域的经验&#xff0c;为大家剖析终端…

养老院管理系统+小程序项目需求分析文档

智慧综合养老服务平台是以业务为牵引、场景为驱动&#xff0c;围绕“老人”业务域&#xff0c;持续沉淀和打磨形成适应不同养老业务发展需要的业务能力&#xff0c;推动业务模式升级&#xff0c;为养老服务提供数字化解决方案&#xff0c;并依托实体站点与养老机构实现线上线下…

SpringBoot集成ES(ElasticSearch)

1.导入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency>导入依赖后&#xff0c;注意在依赖中查看对应的版本是否与本机ES对应 2.创建配置并…

数据结构之二:表

顺序表代码&#xff1a;SData/SqList/SeqList.h Hera_Yc/bit_C_学习 - 码云 - 开源中国 链表相关代码&#xff1a;SData/ListLink/main.c Hera_Yc/bit_C_学习 - 码云 - 开源中国 本文主要讲解的是线性表&#xff08;逻辑线性&#xff09;&#xff0c;对于非线性表不做补充。…

《Python基础》之循环结构

目录 简介 一、for循环 1、基本语法与作用 2、使用 range() 函数配合 for 循环 3、嵌套的for循环 二、while循环 1、基本语法与作用 2、while 循环嵌套 &#xff08;1&#xff09;、while循环与while循环嵌套 &#xff08;2&#xff09;、while循环与for循环嵌套 简介 …

基于LiteFlow的风控系统指标版本控制

个人博客&#xff1a;无奈何杨&#xff08;wnhyang&#xff09; 个人语雀&#xff1a;wnhyang 共享语雀&#xff1a;在线知识共享 Github&#xff1a;wnhyang - Overview 更新日志 最近关于https://github.com/wnhyang/coolGuard此项目更新了如下内容&#xff1a;https://g…

Mysql中的 TEXT 和 BLOB 解析

&#x1f680; 博主介绍&#xff1a;大家好&#xff0c;我是无休居士&#xff01;一枚任职于一线Top3互联网大厂的Java开发工程师&#xff01; &#x1f680; &#x1f31f; 在这里&#xff0c;你将找到通往Java技术大门的钥匙。作为一个爱敲代码技术人&#xff0c;我不仅热衷…