使用EasyExcel导出百万条数据

使用EasyExcel导出百万条数据

应用是基于100W条数据进行的测试
首先:导入相关需要的依赖:

		<dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.16</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.16</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.2.10</version><exclusions><exclusion><groupId>org.apache.poi</groupId><artifactId>poi</artifactId></exclusion><exclusion><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId></exclusion><exclusion><groupId>org.apache.poi</groupId><artifactId>poi-ooxml-schemas</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.16.20</version></dependency><!-- junit --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version><scope>test</scope></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-simple</artifactId><version>1.7.25</version><scope>compile</scope></dependency>

创建所需要的实体类,如下:

@Accessors(chain = true)
@Data
public class ExcelBean {@ExcelProperty("主键id")private String id;@ExcelProperty("姓名")private String name;@ExcelProperty("地址")private String address;@ExcelProperty("年龄")private Integer age;@ExcelProperty("数量")private Integer number;@NumberFormat("#.##")@ExcelProperty("身高")private Double high;@ExcelProperty("距离")private Double distance;@DateTimeFormat("yyyy-MM-dd HH:mm:ss")@ExcelProperty("开始时间")private Date startTime;@ExcelProperty("结束时间")private Date endTime;
}

创建所用到的测试类,如下:

@Slf4j
public class writeExcelByApi {public static final String FILE_NAME = "C:\\Users\\861123001\\Desktop\\mqtt压测软件\\自造数据\\test_04.xlsx";// 每个 sheet 写入的数据public static final int NUM_PER_SHEET = 300000;// 每次向 sheet 中写入的数据(分页写入)public static final int NUM_BY_TIMES = 50000;@Testpublic void writeExcelByApi(){String fileName = FILE_NAME;log.info("导出excel名称={}",fileName);long startTime = System.currentTimeMillis();//调用apiList<ExcelBean> date = getDate();EasyExcel.write(fileName,ExcelBean.class).sheet().doWrite(date);log.info("导出excel结束,数据量={},耗时={}ms", date.size(), System.currentTimeMillis() - startTime);}/*** 获取excel 导出的数据** @return list 集合*/public static List<ExcelBean> getDate(){log.info("开始生成数据");//创建返回数据集合List<ExcelBean> list = new ArrayList<>();Date date = new Date();long startTime = System.currentTimeMillis();for (int i = 0; i < 2000000; i++) {//创建数据对象ExcelBean excelBean = new ExcelBean();ExcelBean excel = excelBean.setId(UUID.randomUUID().toString()).setName("小明" + (10000 + i)).setAddress("浙江省杭州市西湖").setAge(i).setNumber(i + 10000).setHigh(1.234 * i).setDistance(3.14 * i).setStartTime(date).setEndTime(date);list.add(excel);}log.info("数据生成结束,数据量={},耗时={}ms", list.size(), System.currentTimeMillis() - startTime);return list;}
}

EasyExcel 导出 excel 应用优化一:可以通过分sheet来解决超出100万的数据

	@Testpublic void writeExcelByMulSheet() {String fileName = FILE_NAME;log.info("导出excel名称={}",fileName);long startTime = System.currentTimeMillis();//获取数据List<ExcelBean> date = getDate();//获取sheet的个数int sheetNum = date.size() % NUM_PER_SHEET == 0 ? date.size() / NUM_PER_SHEET : date.size() / NUM_PER_SHEET + 1;//指定写入的文件ExcelWriter excelWriter = EasyExcel.write(fileName, ExcelBean.class).build();for (int i = 0; i < sheetNum; i++) {long l = System.currentTimeMillis();//设置sheet的名字,每个sheet名称不能相同String sheetName = "sheet" + i;WriteSheet writeSheet = EasyExcel.writerSheet(i, sheetName).build();//开始根结束行数int startNum = i * NUM_PER_SHEET;int endNum = i == sheetNum - 1 ? date.size() : (i + 1) *  NUM_PER_SHEET;excelWriter.write(date.subList(startNum, endNum), writeSheet);log.info("写入sheet={},数据量{}-{}={},耗时={}ms", sheetName, endNum, startNum, endNum - startNum, System.currentTimeMillis() - l);}//最好放在finally中excelWriter.finish();log.info("导出excel结束,总数据量={},耗时={}ms", date.size(), System.currentTimeMillis() - startTime);}

EasyExcel 导出 excel 应用优化二:数据源 list 太大,直接读取全部的 list 数据导致 OOM
将 list 数据进行分页读取,并进行分页写入到 excel。这样还有个好处,每次每页读取部分数据,然后写入到 excel 中(相当于该批数据已经从内存刷到了磁盘),也增加了写入的效率;poi 中的导出excel,为此专门提供了一个刷新磁盘的 api,具体代码如下

	@Testpublic void writeExcelByMulWrite() {String fileName = FILE_NAME;log.info("导出excel名称={}",fileName);long startTime = System.currentTimeMillis();//获取数据List<ExcelBean> date = getDate();ExcelWriter excelWriter = EasyExcel.write(fileName, ExcelBean.class).build();//适用于针对100万数据以下的写法//WriteSheet writeSheet = EasyExcel.writerSheet("testSheet" ).build();//计算需要写的次数int times = date.size() % NUM_BY_TIMES == 0 ? date.size() / NUM_BY_TIMES : date.size() / NUM_BY_TIMES + 1;for (int i = 0; i < times; i++) {long l = System.currentTimeMillis();WriteSheet writeSheet = EasyExcel.writerSheet("testSheet" + i).build();//开始跟结束行数int startNum = i * NUM_BY_TIMES;int endNum = i == times - 1 ? date.size() : (i + 1) * NUM_BY_TIMES;excelWriter.write(date.subList(startNum, endNum), writeSheet);log.info("写入数量{}-{}={},耗时={}ms", endNum, startNum, endNum - startNum, startTime - l);}//最好写在finally里if (excelWriter != null) {excelWriter.finish();}}

EasyExcel 导出 excel 应用优化三:结合前面两种方案
将 list 数据进行分页读取,并且每个 sheet 分多次写入,且写入到多个 sheet 中

	@Testpublic void writeExcelByMulSheetAndMulWrite() {String fileName = FILE_NAME;log.info("导出excel名称={}", fileName);long startTime = System.currentTimeMillis();//获取数据List<ExcelBean> date = getDate();//获取sheet表数int sheetNum = date.size() % NUM_PER_SHEET == 0 ? date.size() / NUM_PER_SHEET : date.size() / NUM_PER_SHEET + 1;//获取每个sheet导入的次数int writeNumPerSheet = NUM_PER_SHEET % NUM_BY_TIMES == 0 ? NUM_PER_SHEET / NUM_BY_TIMES : NUM_PER_SHEET / NUM_BY_TIMES + 1;// 最后一个 sheet 写入的数量int writeNumLastSheet = date.size() - (sheetNum - 1) * NUM_PER_SHEET;// 最后一个 sheet 写入的次数int writeNumPerLastSheet = writeNumLastSheet % NUM_BY_TIMES == 0 ? writeNumLastSheet / NUM_BY_TIMES : writeNumLastSheet / NUM_BY_TIMES + 1;// 指定写入的文件ExcelWriter excelWriter = EasyExcel.write(fileName, ExcelBean.class).build();for (int i = 0; i < sheetNum; i++) {String sheetName = "sheet" + i;WriteSheet writeSheet = EasyExcel.writerSheet(i, sheetName).build();int writeNum = i == sheetNum - 1 ? writeNumPerLastSheet : writeNumPerSheet; // 每个sheet 写入的次数int endEndNum = i == sheetNum - 1 ? date.size() : (i + 1) * NUM_PER_SHEET; // 每个sheet 最后一次写入的最后行数for (int j = 0; j < writeNum; j++) {long l = System.currentTimeMillis();int startNum = i * NUM_PER_SHEET + j * NUM_BY_TIMES;int endNum = j == writeNum - 1 ? endEndNum : i * NUM_PER_SHEET + (j + 1) * NUM_BY_TIMES;excelWriter.write(date.subList(startNum, endNum), writeSheet);log.info("写入sheet={},数据量={}-{}={},耗时={}", sheetName, endNum, startNum, endNum - startNum, startTime - l);}}// 需要放入 finally 中if (excelWriter != null) {excelWriter.finish();}log.info("导出excel结束,总数据量={},耗时={}ms", date.size(), System.currentTimeMillis() - startTime);}

在这里插入图片描述

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

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

相关文章

springboot系列——IDEA创建项目并运行

springboot Spring Boot是为了简化Spring应用程序的开发和部署而产生的。 Spring Boot提供了一种基于约定优于配置的开发模式。它自动配置了Spring应用程序所需的各种组件和依赖&#xff0c;并提供了简单易用的命令行工具来构建和运行应用程序。 Spring Boot还提供了一套开箱…

Existing installation is up to date

这个报错是之前安装的docker没有删除干净 解决方法&#xff1a; 打开注册表编辑器 然后再搜索栏&#xff1a;HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Docker Desktop 回车 找到Docker Desktop文件夹后&#xff0c;右键删除 重新安装Docker…

Security的入门和流程分析

Security的入门和流程分析 问题&#xff1a;访问一个controller方法之前进行一个权限验证&#xff1f; 在controller里面的每一个handler无论什么访问都要进行一个校验&#xff0c;但是对于login logout 验证码这种Handler处理器是放行的 1.使用过滤器拦截器 注意两者区别 过滤…

DataGrip 数据库备份

一、备份 1、找到需要被备份的数据库demo&#xff0c;右键>Import/Export>Export with mysqldump 2、配置路径 点击run&#xff0c;等待完成 导出成功 二、还原 选择 需要导入的数据库>右键>Import/Export>Restore with ‘mysql’ 点击run&#xff0c;刷…

基于seatunnel实现mysql同步clickhouse验证

场景&#xff1a; 需求想要实现mysql同步到clickhouse&#xff0c;seatunnel部署见前面文档linux环境seatunnel安装运行-CSDN博客。 官方说明文档 Clickhouse | Apache SeaTunnel mysql同步配置 server-id1 log_bin/var/lib/mysql/bin.log binlog_formatROW #binlog-do-db 具…

为什么说上了金蝶、用友系统后,下一步是部署BI?

经常有些不熟悉BI工具的用户问我&#xff1a;金蝶、用友系统和BI工具与什么区别&#xff0c;为什么说上了金蝶、用友系统后&#xff0c;下一步就是部署BI&#xff1f;这两个系统工具的功能不重叠吗&#xff1f; 首先&#xff0c;要了解金蝶、用友系统和BI工具的各自作用。 金…

理解 Node.js 中的事件循环

你已经使用 Node.js 一段时间了&#xff0c;构建了一些应用程序&#xff0c;尝试了不同的模块&#xff0c;甚至对异步编程感到很舒适。但是有些事情一直在困扰着你——事件循环&#xff08;Event Loop&#xff09;。 如果你像我一样&#xff0c;花费了无数个小时阅读文档和观看…

虚幻UE 增强输入-触发器

上一篇增强输入基础&#xff1a;虚幻UE 增强输入-第三人称模板增强输入分析与扩展 主要对第三人称模板的增强输入进行分析、复刻和扩展 本篇将会对增强输入中的触发器中的各参数进行讲解 文章目录 前言触发器参数1、下移TriggerDown2、已按下TriggerPressed3、已松开TriggerRel…

cesium粒子爆炸效果

效果&#xff1a; //添加爆炸模型window.swpecesium.addEntity.addModel({id: "model",position: {lon: 116.34516786934411,lat: 39.99753297677145,},config: {url: "./model/baozha/scene.gltf",minSize: 200,maxSize: 300,},});var scene viewer.scen…

接口测试测什么?一个简单问题把我难住了!

那么设计测试用例时我们主要考虑如下几个方面&#xff1a; 01、功能测试 接口的功能是否正确实现了 接口是否按照设计文档中来实现 &#xff08;比如username参数写为了user&#xff0c;那么这就不符合&#xff0c;因为接口文档在整个开发中都需要使用&#xff0c;所以接口实…

60V降12V3A降压芯片WT6037

60V降12V3A降压芯片WT6037 WT6037是一款高压同步降压转换器&#xff0c;可在10V到90V的宽输入电压范围内工作适用于宽电压输入12V-72V电池组系统降压和60V-90V降压应用。WT6037可提供4A连续负载电流&#xff0c;转换效达92%。 WT6037采用具有内置补偿的固定频率峰值电流控…

Element ui 改变el-transfer 穿梭框的大小

修改el-transfer 左右两个穿梭框的高度和宽度&#xff0c;具体效果如下正常大小的穿梭框修改之后的&#xff0c;主要在style中加上如下样式即可 /deep/ .el-transfer-panel{ width: 470px; /* 左右两个穿梭框的高度和宽度 */ height: 450px; } /deep/ .el-transfer-panel__li…

element的Table表格组件树形数据与非懒加载

1.代码实现 <template><div><el-row :gutter"10" class"mb8"><el-col :span"1.5"><el-button type"info" plain icon"el-icon-sort" size"mini" click"toggleExpandAll"&g…

Java面试题之集合篇

前言 本篇主要总结JAVA面试中关于集合相关的高频面试题。本篇的面试题基于网络整理以及自己的总结编辑。在不断的完善补充哦。欢迎小伙伴们在评论区发表留言哦&#xff01; 1、基础 1.1、Java 集合框架有哪些&#xff1f; Java 集合框架&#xff0c;大家可以看看 《Java 集…

C#上位机与欧姆龙PLC的通信10----开发专用的通讯工具软件(WPF版)

1、介绍 上节开发了一个winform版的通讯测试工具&#xff0c;这节再搞个wpf版的&#xff0c;wpf是什么&#xff1f;请自行百度&#xff0c;也可以看前面的博客&#xff0c;WPF真入门教程&#xff0c;wpf的界面效果是比winform漂亮&#xff0c;因为wpf使用了web项目中的css样式…

java发送邮件到qq邮箱

自己的授权码自己记好 引入依赖 <dependency><groupId>com.sun.mail</groupId><artifactId>javax.mail</artifactId><version>1.6.2</version> </dependency> <dependency><groupId>javax.mail</groupId>&…

Socket与TCP的关系

前言 相信大家对于TCP已经非常熟悉了&#xff0c;学习过计算机网络的同学对于它的连接和断开流程应该已经烂熟于心了吧。 那么Socket是什么&#xff1f; Socket是应用层与TCP/IP协议簇通信的中间软件抽象层&#xff0c;它是一组接口。在设计模式中&#xff0c;Socket其实就是…

车位关键点检测-车位识别-车辆识别检测(教程+代码)

车位关键点检测、车位识别和车辆识别检测是现代智能交通系统中的重要技术&#xff0c;它们在提高停车管理效率和交通流畅度方面起着重要作用。以下是对这三个技术的分点阐述&#xff1a; 1. 车位关键点检测&#xff1a; 车位关键点检测是指通过计算机视觉技术&#xff0c;自动…

Docker中镜像的相关操作

1.辅助操作 docker version&#xff1a;用查看docker客户端引擎和server端引擎版本信息。 docker info&#xff1a;用来查看docker引擎的详细信息。 docker --help&#xff1a;用来查看帮助信息。 2.镜像Image docker images&#xff1a;查看当前本地仓库中存在哪些镜像。 …

解决uniapp打包成apk后uni.getStorageSync获取不到值

uniapp写的项目&#xff0c;在hbuilderx中云打包成apk后我在登录存储的token死都获取不到&#xff0c;导致后续接口请求头没有token连接不到接口&#xff0c;只有运行到手机或者模拟器还有打包成apk后是获取不到&#xff0c;其他的小程序还有网页都可以获取到 试过了很多种方法…