Java8如何让Excel的读写变得更加简单高效
ztj100 2024-11-05 13:27 12 浏览 0 评论
在POI的使用过程中,对大多数API User来说经常面临两个问题,这也是GridExcel 致力解决的问题。
问题1. 仅使用简单的导入导出功能,但每次业务的数据对象结构不同,需要重新编写处理方法,很麻烦!
解决方法
将Excel处理逻辑抽取出来,封装成工具类。
封装条件
与大多数Java API一样,POI把更多的精力放在高级功能的处理上,比如Formula(公式)、Conditional Formatting(条件格式)、Zoom(缩放)等。对于仅仅做数据导入导出功能的API User,很少使用这些高级特性,这允许API用户对POI的使用进行简单的封装。
封装方式
无论是读是写,我们都需要解决Excel中的Columns(列)与Java数据对象Fields(字段)的映射关系,将这种映射关系作为参数(Map对象HashMap或LinkedHashMap),传递给工具类。
对于Columns不难理解,它可以是有序的数字或字母,也可以是其它字符串用来作为首行,表示该列数据的含义。
对于Fields,它的处理需要兼容复杂情况,如下:
value == true?完成:失败;
反射
首先想到,也是大多数封装者都在使用的方式是就是Reflection API ,从上文函数编程 章节我们了解到,反射重量级,会降低代码的性能,同时对复杂情况的处理支持性不够好。
反射+注解
这种方式可以更好的支持复杂情况,但是反射依然会降低性能,同时注解对数据对象会造成代码侵入,而且对该工具类封装者的其他使用者无疑会增加学习成本。
匿名内部类
这种方式也可以很好的支持复杂情况,但是使用匿名内部类的语法显然患有“垂直问题”(这意味着代码需要太多的线条来表达基本概念),太过冗杂。
至于性能,应该也不如直接传递函数来的快吧。
函数接口(Lambda)
这种方式是基于第5条方法调用的字节码指令invokeDynamic 实现的,直接传递函数代码块,很好的支持复杂情况,性能较高,代码编写更简单结构更加简洁,而且对数据对象代码零侵入。
当然如果你还没有使用Java1.8或更高版本,那么你可以参考匿名内部类 或反射+注解 ,不过还是推荐反射+注解 ,Alibaba/easyexcel【https://github.com/alibaba/easyexcel】 对你来说会是不错的选择。
问题2. Excel导入或导出数据量比较大,造成内存溢出 或频繁的Full GC ,该如何解决?
解决方法
- 读Excel —— eventmodel写Excel —— streaming.SXSSFWorkbook
原理
POI的使用对我们来说很常见,对下面两个概念应该并不陌生:
- HSSFWorkbook(处理97(-2007) 的.xls)XSSFWorkbook(处理2007 OOXML (.xlsx) )
但是对于eventmodel 和streaming.SXSSFWorkbook 就很少接触了,它们是POI提供的专门用来解决内存占用问题的low level API (低级API),使用它们可以读写数据量非常大的Excel,同时可以避免内存溢出 或频繁的Full GC 。【https://poi.apache.org/components/spreadsheet/how-to.html】
- eventmodel ,用来读Excel,并没有将Excel整个加载到内存中,而是允许用户从InputStream 每读取一些信息,就交给回调函数 或监听器 ,至于丢弃,存储还是怎么处理这些内容,都交由用户。streaming.SXSSFWorkbook ,用来写Excel(是对XSSFWorkbook的封装,仅支持.xlsx),通过滑动窗口 来实现,只在内存中保留滑动窗口允许存在的行数,超出的行Rows被写出到临时文件,当调用write(OutputStream stream) 方法写出内容时,再直接从临时内存写出到目标OutputStream 。SXSSFWorkbook 的使用会产生一些局限性。Only a limited number of rows are accessible at a point in time.Sheet.clone() is not supported.Formula evaluation is not supported
解决途径
- https://github.com/liuhuagui/gridexcel 基于Java函数编程(Lambda),支持流式API,使用环境Java1.8或更高,学习成本:Lambdahttps://github.com/alibaba/easyexcel 基于反射+注解+监听器,使用环境Java1.6或以上,学习成本:模型注解
实际上POI官网已经给了用户使用示例,而上述两个工具都只是做了自己的封装实现,使用者只需要拿来用就好。
快速使用
<dependency> <groupId>com.github.liuhuagui</groupId> <artifactId>gridexcel</artifactId> <version>2.2</version> </dependency>
GridExcel.java
GridExcel.java提供了多种静态方法,可以直接使用,具体式例可参考测试代码(提供了测试数据和测试文件):
- https://github.com/liuhuagui/gridexcel/blob/master/src/test/java/ReadTest.javahttps://github.com/liuhuagui/gridexcel/blob/master/src/test/java/WriteTest.java
流式API
/** * 业务逻辑处理方式三选一: * 1.启用windowListener,并将业务逻辑放在该函数中。 * 2.不启用windowListener,使用get()方法取回全部数据集合,做后续处理。 * 3.readFunction函数,直接放在函数中处理 或 使用final or effective final的局部变量存放这写数据,做后续处理。 * 注意:使用EventModel时readFunction函数的输入为每行的cell值集合List<String>。 * @throws Exception */ @Test public void readXlsxByEventModel() throws Exception { InputStream resourceAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("2007.xlsx"); GridExcel.readByEventModel(resourceAsStream,TradeOrder.class,ExcelType.XLSX) .window(2,ts -> System.out.println(JSON.toJSONString(ts)))//推荐在这里执行自己的业务逻辑 .process(cs ->{ TradeOrder tradeOrder = new TradeOrder(); tradeOrder.setTradeOrderId(Long.valueOf(cs.get(0))); Consultant consultant = new Consultant(); consultant.setConsultantName(cs.get(3)); tradeOrder.setConsultant(consultant); tradeOrder.setPaymentRatio(cs.get(16)); return tradeOrder; },1); } /** * 使用Streaming UserModel写出数据到Excel * @throws Exception */ @Test public void writeExcelByStreaming() throws Exception { GridExcel.writeByStreaming(TradeOrder.class) .head(writeFunctionMap())//对象字段到Excel列的映射 .createSheet() .process(MockData.data())//模拟数据。在这里设置业务数据集合。 .write(FileUtils.openOutputStream(new File("/excel/test.xlsx"))); }
ReadExcel
ReadExcelByUserModel
Use user model to read excel file. userModel ——
- 缺点 :内存消耗大,会将excel信息全部加载到内存再进行处理。优点 :现成的API,使用和理解更简单。使用场景 :可以处理数据量较小的Excel。
ReadExcelByEventModel
Use event model to read excel file. eventModel ——
- 缺点 :没有现成的API,使用和理解较为复杂,适合中高级程序员(GridExcel的目标之一就是让EventModel的使用变得简单)优点 :非常小的内存占用,并没有在一开始就将所有内容加载到内存中,而是把主体内容的处理(存储,使用,丢弃)都交给了用户,用户可以自定义监听函数来处理这些内容。使用场景 :可以处理较大数据量的Excel,避免OOM和频繁FullGC
WriteExcel
WriteExcelByUserModel
Use user model to write excel file. userModel ——
- 缺点 :会将产生的spreadsheets对象整个保存在内存中,所以write Excel的大小受到堆内存(Heap space)大小限制。优点 :使用和理解更简单。使用场景 :可以写出数据量较小的Excel。
WriteExcelByStreaming
Use API-compatible streaming extension of XSSF to write very large excel file. streaming userModel——
- 缺点 :仅支持XSSF;Sheet.clone() is not supported;Formula evaluation is not supported;Only a limited number of rows are accessible at a point in time.
- 优点 :通过滑动窗口来实现,内存中只保留指定size of rows的内容,超出部分被写出到临时文件,write Excel的大小不再受到堆内存(Heap space)大小限制。使用场景 :可以写出非常大的Excel。
Issues
在使用工具过程中出现问题,有功能添加或改动需求的可以向作者提Issue:https://github.com/liuhuagui/gridexcel/issues
比如说,想要增加对首行以外的行列做样式扩展 需要java学习路线图的私信笔者“java”领取哦!另外喜欢这篇文章的可以给笔者点个赞同,关注一下,每天都会分享Java相关文章!还有不定时的福利赠送,包括整理的学习资料,面试题,源码等~~
相关推荐
- Whoosh,纯python编写轻量级搜索工具
-
引言在许多应用程序中,搜索功能是至关重要的。Whoosh是一个纯Python编写的轻量级搜索引擎库,可以帮助我们快速构建搜索功能。无论是在网站、博客还是本地应用程序中,Whoosh都能提供高效的全文搜...
- 如何用Python实现二分搜索算法(python二分法查找代码)
-
如何用Python实现二分搜索算法二分搜索(BinarySearch)是一种高效的查找算法,适用于在有序数组中快速定位目标值。其核心思想是通过不断缩小搜索范围,每次将问题规模减半,时间复杂度为(O...
- 路径扫描 -- dirsearch(路径查找器怎么使用)
-
外表干净是尊重别人,内心干净是尊重自己,干净,在今天这个时代,应该是一种极高的赞美和珍贵。。。----网易云热评一、软件介绍Dirsearch是一种命令行工具,可以强制获取web服务器中的目录和文件...
- 78行Python代码帮你复现微信撤回消息!
-
来源:悟空智能科技本文约700字,建议阅读5分钟。本文基于python的微信开源库itchat,教你如何收集私聊撤回的信息。...
- 从零开始学习 Python!2《进阶知识》 Python进阶之路
-
欢迎来到Python学习的进阶篇章!如果你说已经掌握了基础语法,那么这篇就是你开启高手之路的大门。我们将一起探讨面向对象编程...
- 白帽黑客如何通过dirsearch脚本工具扫描和收集网站敏感文件
-
一、背景介绍...
- Python之txt数据预定替换word预定义定位标记生成word报告(四)
-
续接Python之txt数据预定替换word预定义定位标记生成word报告(一)https://mp.toutiao.com/profile_v4/graphic/preview?pgc_id=748...
- Python——字符串和正则表达式中的反斜杠('\')问题详解
-
在本篇文章里小编给大家整理的是关于Python字符串和正则表达式中的反斜杠('\')问题以及相关知识点,有需要的朋友们可以学习下。在Python普通字符串中在Python中,我们用'\'来转义某些普通...
- Python re模块:正则表达式综合指南
-
Python...
- python之re模块(python re模块sub)
-
re模块一.re模块的介绍1.什么是正则表达式"定义:正则表达式是一种对字符和特殊字符操作的一种逻辑公式,从特定的字符中,用正则表达字符来过滤的逻辑。(也是一种文本模式;)2、正则表达式可以帮助我们...
- MySQL、PostgreSQL、SQL Server 数据库导入导出实操全解
-
在数字化时代,数据是关键资产,数据库的导入导出操作则是连接数据与应用场景的桥梁。以下是常见数据库导入导出的实用方法及代码,包含更多细节和特殊情况处理,助你应对各种实际场景。一、MySQL数据库...
- Zabbix监控系统系列之六:监控 mysql
-
zabbix监控mysql1、监控规划在创建监控项之前要尽量考虑清楚要监控什么,怎么监控,监控数据如何存储,监控数据如何展现,如何处理报警等。要进行监控的系统规划需要对Zabbix很了解,这里只是...
- mysql系列之一文详解Navicat工具的使用(二)
-
本章内容是系列内容的第二部分,主要介绍Navicat工具的使用。若查看第一部分请见:...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- Whoosh,纯python编写轻量级搜索工具
- 如何用Python实现二分搜索算法(python二分法查找代码)
- 路径扫描 -- dirsearch(路径查找器怎么使用)
- 78行Python代码帮你复现微信撤回消息!
- 从零开始学习 Python!2《进阶知识》 Python进阶之路
- 白帽黑客如何通过dirsearch脚本工具扫描和收集网站敏感文件
- Python之txt数据预定替换word预定义定位标记生成word报告(四)
- 假期苦短,我用Python!这有个自动回复拜年信息的小程序
- Python——字符串和正则表达式中的反斜杠('\')问题详解
- Python re模块:正则表达式综合指南
- 标签列表
-
- idea eval reset (50)
- vue dispatch (70)
- update canceled (42)
- order by asc (53)
- spring gateway (67)
- 简单代码编程 贪吃蛇 (40)
- transforms.resize (33)
- redisson trylock (35)
- 卸载node (35)
- np.reshape (33)
- torch.arange (34)
- node卸载 (33)
- npm 源 (35)
- vue3 deep (35)
- win10 ssh (35)
- exceptionininitializererror (33)
- vue foreach (34)
- idea设置编码为utf8 (35)
- vue 数组添加元素 (34)
- std find (34)
- tablefield注解用途 (35)
- python str转json (34)
- java websocket客户端 (34)
- tensor.view (34)
- java jackson (34)