Excel大数据量导入导出

github源码 地址(更详细) : https://github.com/alibaba/easyexcel

文档:读Excel(文档已经迁移)

B 站视频 : https://www.bilibili.com/video/BV1Ff4y1U7Qc

一、JAVA解析EXCEL工具EasyExcel

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

64M内存1分钟内读取75M(46W行25列)的Excel

二、EasyExcel的使用

EasyExcel的相关依赖

添加 maven 依赖
<!-- Alibaba Excel 依赖 -->
<!--它提供了高性能的读写功能,特别适合处理大型 Excel 文件 -->
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.3.4</version>
</dependency>
<!-- Apache POI 依赖 -->
<!--poi 是 Apache POI 项目的核心库,提供了读写 Microsoft Office 格式文件的基础功能,包括 .xls 文件 -->
<dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.1.2</version>
</dependency>
<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>4.1.2</version>
</dependency>
<dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml-schemas</artifactId><version>4.1.2</version>
</dependency>
<!-- SLF4J 和 Logback 依赖 -->
<!-- 日志 -->
<dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.2.11</version>
</dependency>

三、Excel

创建实体类
@ExcelProperty 注解的 value 属性是一个数组类型 , 设置多个 head 时会自动合并,用于指定Excel表格中该字段的显示名称(起名字)
@NoArgsConstructor @AllArgsConstructor Lombok 库提供的注解
@NoArgsConstructor 生成一个无参构造函数(即没有参数的构造函数)
@AllArgsConstructor 生成一个全参构造函数(即包含类中所有字段的构造函数)
@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public class User {@ExcelProperty(value = "用户编号")private Integer userId;@ExcelProperty(value = "姓名")private String userName;@ExcelProperty(value = "性别")private String gender;@ExcelProperty(value = "工资")private Double salary;@ExcelProperty(value = "入职时间")private Date hireDate;// lombok 会生成getter/setter方法
}
1.简单写入方法一
    /*** 简单写方法一*/@Testpublic void text01(){//创建一个Excel文档String fileName = "D:\\excel\\user1.xlsx";//根据user模板构建数据List<User> users = new ArrayList<>();User user1 = new User(1,"张三","男",666.66,new Date());User user2 = new User(2,"张三","男",666.66,new Date());User user3 = new User(3,"张三","男",666.66,new Date());User user4 = new User(4,"张三","男",666.66,new Date());users.add(user1);users.add(user2);users.add(user3);users.add(user4);//向Excel表格中写数据EasyExcel.write(fileName,User.class).sheet("用户信息").doWrite(users);}
2.简单写入方法二
 /*** 简单写方法二*/@Testpublic void text02(){//创建一个Excel文档String fileName = "D:\\excel\\user2.xlsx";//根据user模板构建数据List<User> users = new ArrayList<>();User user1 = new User(1,"张三","男",666.66,new Date());User user2 = new User(2,"张三","男",666.66,new Date());User user3 = new User(3,"张三","男",666.66,new Date());User user4 = new User(4,"张三","男",666.66,new Date());users.add(user1);users.add(user2);users.add(user3);users.add(user4);//向Excel表格中写数据//创建ExcelWriter对象ExcelWriter excelWriter = EasyExcel.write(fileName, User.class).build();//创建sheet对象WriteSheet writeSheet = EasyExcel.writerSheet("用户信息").build();excelWriter.write(users,writeSheet);//关闭ExcelWriter对象(一定要关闭,不然会导致内存溢出)excelWriter.finish();}
 3.排除掉某些不想添加的字段
   /*** 排除掉模板中的某几项属性*/@Testpublic void text03(){//创建一个Excel文档String fileName = "D:\\excel\\user3.xlsx";//根据user模板构建数据List<User> users = new ArrayList<>();User user1 = new User(1,"张三","男",666.66,new Date());User user2 = new User(2,"张三","男",666.66,new Date());User user3 = new User(3,"张三","男",666.66,new Date());User user4 = new User(4,"张三","男",666.66,new Date());users.add(user1);users.add(user2);users.add(user3);users.add(user4);//设置排除的属性Set<String> set = new HashSet<>();set.add("salary");set.add("hireDate");//向Excel表格中写数据EasyExcel.write(fileName, User.class).excludeColumnFiledNames(set).sheet("用户信息").doWrite(users);}
4.复杂头数据写入
@ExcelProperty 注解的 value 属性是一个数组类型 , 设置多个 head 时会自动合并
/*** 复杂头实体类*/
@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public class ComplexHeadUser {@ExcelProperty(value = {"group1", "用户编号"}, index = 0)private Integer userId;@ExcelProperty(value = {"group1", "姓名"}, index = 1)private String userName;@ExcelProperty(value = {"group2", "入职时间"}, index = 2)private Date hireDate;
}
  /*** 复杂头*/@Testpublic void text05(){//创建一个Excel文档String fileName = "D:\\excel\\user5.xlsx";//根据user模板构建数据List<ComplexHeadUser> users = new ArrayList<>();ComplexHeadUser user1 = new ComplexHeadUser(1,"张三",new Date());ComplexHeadUser user2 = new ComplexHeadUser(2,"张三",new Date());ComplexHeadUser user3 = new ComplexHeadUser(3,"张三",new Date());users.add(user1);users.add(user2);users.add(user3);//向Excel表格中写数据EasyExcel.write(fileName, ComplexHeadUser.class).sheet("用户信息").doWrite(users);}
//或
@Test
public void testWriteExcel6() {String filename = "D:\\study\\user6.xlsx";List<ComplexHeadUser> users = new ArrayList<>();for (int i = 1; i <= 10; i++) {ComplexHeadUser user = ComplexHeadUser.builder().userId(i).userName("大哥" + i).hireDate(new Date()).build();users.add(user);}// 向Excel中写入数据EasyExcel.write(filename, ComplexHeadUser.class).sheet("用户信息").doWrite(users);
}
处理百万级批量数据
处理百万级批量数据时,性能和内存管理是关键问题。 EasyExcel 提供了一些优化策略来处理大规模数据,包括分页读取和分批写入。下面是一些常用的优化技巧:
1. 分批写入
对于写操作,可以使用 EasyExcel 的分批写入功能,这样可以避免一次性加载大量数据导致的内存溢 出问题。
假设您有一个 User 类,定义如下:
/*** 创建User类模板,通过User类模板向Excel表格中写数据*  @ExcelProperty这个注解用于指定Excel表格中该字段的显示名称(起名字)*/
@NoArgsConstructor
@AllArgsConstructor
@Data
@Builder
public class User {@ExcelProperty(value = "用户编号")private Integer userId;@ExcelProperty(value = "姓名")private String userName;@ExcelProperty(value = "性别")private String gender;@ExcelProperty(value = "工资")private Double salary;@ExcelProperty(value = "入职时间")private Date hireDate;// lombok 会生成getter/setter方法}
 /*** 处理百万级批量数据*/@Testpublic void text06(){//创建一个Excel文档String fileName = "D:\\excel\\user6.xlsx";// 确保目录存在File directory = new File("D:\\excel");if (!directory.exists()) {directory.mkdirs();}// 分批大小int batchSize = 10000;// 创建 ExcelWriter 对象ExcelWriter excelWriter = EasyExcel.write(fileName, User.class).build();for (List<User> data : dataList(batchSize)) {// 创建 sheet 对象WriteSheet writeSheet = EasyExcel.writerSheet("用户信息").build();// 写数据excelWriter.write(data, writeSheet);}excelWriter.finish();System.out.println("Excel文件已成功创建!");}private List<List<User>> dataList(int batchSize) {List<List<User>> allData = new ArrayList<>();int totalRecords = 1000000; // 假设有 100 万条记录for (int i = 0; i < totalRecords; i += batchSize) {List<User> batch = new ArrayList<>();for (int j = 0; j < batchSize && i + j < totalRecords; j++) {User user = User.builder().userId(i + j + 1).userName("用户" + (i + j + 1)).gender(j % 2 == 0 ? "男" : "女").salary(10000.0 + (i + j) * 1000.0).hireDate(new Date()).build();batch.add(user);}allData.add(batch);}return allData;}
解释
1. 分批大小 batchSize 定义了每批写入的数据量。可以根据实际需求调整这个值。
2. 创建 ExcelWriter 对象 :使用 EasyExcel.write 方法创建 ExcelWriter 对象,并指定文件路径和数据模型类。
3. 分批写入数据 dataList 方法生成分批的数据列表,每次调用 doWrite 方法写入一批数据。
5.分页读取
对于读操作,可以使用 EasyExcel 的分页读取功能,每次只读取一部分数据进行处理。
1. 创建 User
首先,定义一个 User 类,用于表示 Excel 文件中的每一行数据
package com.hz.pojo;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User {@ExcelProperty(value = "用户编号")private Integer userId;@ExcelProperty(value = "姓名")private String userName;@ExcelProperty(value = "性别")private String gender;@ExcelProperty(value = "工资")private Double salary;@ExcelProperty(value = "入职时间")private Date hireDate;
}
2. 创建 UserListener
实现 AnalysisEventListener 接口,用于处理读取的数据
package com.hz.listener;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.hz.pojo.User;
import java.util.ArrayList;
import java.util.List;
public class UserListener extends AnalysisEventListener<User> {private static final int BATCH_COUNT = 1000; // 每次处理的数据量private List<User> list = new ArrayList<>(BATCH_COUNT);private int batchNumber = 1; // 记录当前处理的批次/*** 每读取一行数据时调用此方法。* @param user 当前行的数据对象* @param context 上下文对象,包含读取状态等信息*/@Overridepublic void invoke(User user, AnalysisContext context) {list.add(user); // 将当前行的数据对象添加到列表中if (list.size() >= BATCH_COUNT) {saveData(); // 如果列表达到批量大小,则保存数据list.clear(); // 清空列表,准备下一批数据batchNumber++; // 增加批次计数}}/*** 所有数据读取完成后调用此方法。* @param context 上下文对象,包含读取状态等信息*/@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {saveData(); // 处理剩余的数据System.out.println("所有数据处理完成,共处理了 " + (batchNumber - 1) + " 批次数据。");}/*** 保存数据的方法。* 这里可以将数据保存到数据库或其他地方。*/private void saveData() {// 这里可以将数据保存到数据库或其他地方System.out.println("正在处理第 " + batchNumber + " 批次数据,共 " +list.size() + " 条记录。");for (User user : list) {System.out.println(user); // 打印数据,实际应用中可以保存到数据库}}/*** 处理读取过程中出现的异常。* @param exception 异常对象* @param context 上下文对象,包含读取状态等信息* @throws Exception 如果需要抛出异常*/@Overridepublic void onException(Exception exception, AnalysisContext context) throw Exception{System.err.println("读取数据时发生异常: " + exception.getMessage());// 可以在这里记录日志或进行其他错误处理}
package com.hz.test;
import com.alibaba.excel.EasyExcel;
import com.hz.listener.UserListener;
import org.junit.jupiter.api.Test;
public class ReadTest {
@Test
public void testPageReadExcel() {String filename = "D:\\excel\\users.xlsx";// 创建监听器UserListener listener = new UserListener();// 读取 Excel 文件EasyExcel.read(filename, User.class, listener).sheet().doRead();System.out.println("Excel文件读取完成!");}
}

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

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

相关文章

Java基础知识总结(四十八)--TCP传输、TCP客户端、TCP服务端

**TCP传输&#xff1a;**两个端点的建立连接后会有一个传输数据的通道&#xff0c;这通道称为流&#xff0c;而且是建立在网络基础上的流&#xff0c;称之为socket流。该流中既有读取&#xff0c;也有写入。 **tcp的两个端点&#xff1a;**一个是客户端&#xff0c;一个是服务…

HCIA项目实践--RIP相关原理知识面试问题总结回答

9.4 RIP 9.4.1 补充概念 什么是邻居&#xff1f; 邻居指的是在网络拓扑结构中与某一节点&#xff08;如路由器&#xff09;直接相连的其他节点。它们之间可以直接进行通信和数据交互&#xff0c;能互相交换路由信息等&#xff0c;以实现网络中的数据转发和路径选择等功能。&am…

【CXX-Qt】0 Rust与Qt集成实践指南(CXX-Qt)

CXX-Qt 是一个用于在 Rust 和 Qt 之间实现安全互操作的库。与通常的 Rust Qt 绑定不同&#xff0c;它提供了一种不同的方式来桥接 Qt 代码和 Rust 代码。CXX-Qt 认识到 Qt 和 Rust 代码具有不同的习惯&#xff0c;因此不能直接从一个语言包装到另一个语言。相反&#xff0c;它使…

计算机毕业设计SpringBoot校园二手交易小程序 校园二手交易平台(websocket消息推送+云存储+双端+数据统计)(源码+文档+运行视频+讲解视频)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

1.2 JSON数据类型与Java类型对应关系

以下是 JSON数据类型与Java类型对照表 的详细说明&#xff0c;涵盖基础类型和常见复杂场景的映射关系&#xff1a; 一、基础类型映射 JSON 数据类型Java 类型示例说明字符串String"name":"John" → String name布尔值boolean/Boolean"active":t…

Django开发入门 – 4.创建Django app

Django开发入门 – 4.创建Django app Create A Django App Under An Existing Project By JacksonML 1. 什么是Django app? Django项目面向Web应用程序&#xff0c;它会由一个或多个子模块组成&#xff0c;这些子模块称为apps。 Django apps负责执行完整Web应用程序中涉及…

深度剖析工厂模式:Java中的对象创建艺术与实践优化

在软件工程中&#xff0c;对象创建是系统设计的核心问题之一。如何优雅地解耦对象的创建与使用&#xff0c;如何应对复杂对象的构造过程&#xff0c;如何提升代码的可维护性和扩展性&#xff1f;工厂模式&#xff08;Factory Pattern&#xff09; 正是解决这些问题的经典设计模…

八、OSG学习笔记-

前一章节&#xff1a; 七、OSG学习笔记-碰撞检测-CSDN博客https://blog.csdn.net/weixin_36323170/article/details/145558132?spm1001.2014.3001.5501 一、了解OSG图元加载显示流程 本章节代码&#xff1a; OsgStudy/wids CuiQingCheng/OsgStudy - 码云 - 开源中国https:…

shell脚本自动安装MySQL8

环境&#xff1a;centos7版本&#xff1a;8.0.28安装包&#xff1a;mysql-8.0.28-linux-glibc2.12-x86_64.tar.xz 二进制包要求&#xff1a;安装包和shell脚本在同一目录下执行方式&#xff1a;sudo ./install_mysql8.sh #!/bin/bash# 定义MySQL安装目录和压缩包名称MYSQL_DIR…

pdsh 2.29 源码编译安装教程

pdsh 2.29 源码编译安装教程 简介 pdsh (Parallel Distributed Shell) 是一个高效的多服务器并行shell命令执行工具。本文将详细介绍如何从源码编译安装pdsh 2.29版本。 环境要求 Linux操作系统gcc编译器make工具足够的磁盘空间&#xff08;建议至少1GB可用空间&#xff09…

微信小程序医院挂号系统

第3章 系统设计 3.1系统体系结构 系统的体系结构非常重要&#xff0c;往往决定了系统的质量和生命周期。针对不同的系统可以采用不同的系统体系结构。本系统为微信小程序医院挂号系统&#xff0c;属于开放式的平台&#xff0c;所以在管理端体系结构中采用B/s。B/s结构抛弃了固…

人工智能浪潮下脑力劳动的变革与重塑:挑战、机遇与应对策略

一、引言 1.1 研究背景与意义 近年来&#xff0c;人工智能技术发展迅猛&#xff0c;已成为全球科技领域的焦点。从图像识别、语音识别到自然语言处理&#xff0c;从智能家居、智能交通到智能医疗&#xff0c;人工智能技术的应用几乎涵盖了我们生活的方方面面&#xff0c;给人…

爬虫抓取过程的详细步骤

1. 目标网站分析 在开始编写爬虫之前&#xff0c;首先需要对目标网站进行详细的分析。这一步是整个爬虫开发过程中非常重要的环节&#xff0c;因为它直接决定了爬虫的效率和成功率。 确定目标数据&#xff1a;明确你想要抓取的数据&#xff0c;例如商品名称、价格、描述、图片…

嵌入式八股文面试题(二)C语言算法

相关概念请查看文章&#xff1a;C语言概念。 1. 如何实现一个简单的内存池&#xff1f; 简单实现&#xff1a; #include <stdio.h> #include <stdlib.h>//内存块 typedef struct MemoryBlock {void *data; // 内存块起始地址struct MemoryBlock *next; // 下一个内…

网络安全-攻击路径

以下是互联网场景下常见的攻击路径分类及详细说明&#xff0c;以分层结构呈现&#xff1a; 一、网络层攻击路径 DDoS攻击 原理&#xff1a;通过僵尸网络发起海量请求淹没目标服务器示例&#xff1a;SYN Flood攻击、HTTP洪泛攻击影响&#xff1a;服务不可用&#xff0c;带宽资源…

【嵌入式Linux应用开发基础】open函数与close函数

目录 一、open函数 1.1. 函数原型 1.2 参数说明 1.3 返回值 1.4. 示例代码 二、close函数 2.1. 函数原型 2.2. 示例代码 三、关键注意事项 3.1. 资源管理与泄漏防范 3.2. 错误处理的严谨性 3.3. 标志&#xff08;flags&#xff09;与权限&#xff08;mode&#xff…

MT6835 21位 磁编码器 SPI 平台无关通用驱动框架 STM32

MT6835 21位 磁编码器 SPI 平台无关通用驱动框架 STM32 1. 获取代码&#xff1a;2. 加入你的项目2.1 以 STM32 为例:2.2 以 ESP-IDF 为例: 3. 对接 API3.1 以 STM32 为例&#xff1a; 4. 更多函数说明5. 写入 EEPROM 示例 MT6835 Framework 纯C语言实现&#xff0c;跨平台&…

24、深度学习-自学之路-卷积神经网络

一、你怎么理解卷积神经网络呢&#xff0c;我的理解是当你看一个东西的时候&#xff0c;你的眼睛距离图片越近&#xff0c;你看到的东西就越清晰&#xff0c;但是如果你看到的图片只是整个物体的一小部分&#xff0c;那么你将不知道你看到的物品是什么&#xff0c;因为关注整体…

集合家族详情

一、Java集合框架全景图 1.1 核心接口层次结构 graph TDA[Iterable] --> B[Collection]B --> C1[List]B --> C2[Set]B --> C3[Queue]C1 --> D1[ArrayList]C1 --> D2[LinkedList]C2 --> E1[HashSet]C2 --> E2[TreeSet]C3 --> F1[PriorityQueue]G[M…

ArcGIS基础知识之ArcMap基础设置——ArcMap选项:常规选项卡设置及作用

作为一名 GIS 从业者,ArcMap 是我们日常工作中不可或缺的工具。对于初学者来说,掌握 ArcMap 的基础设置是迈向 GIS 分析与制图的第一步。今天,就让我们一起深入了解 ArcMap 选项中常规选项卡的各个设置,帮助大家更好地使用这款强大的软件。 在 ArcMap 中,常规选项卡是用户…