如何解决Java EasyExcel 导出报内存溢出

如何解决Java EasyExcel 导出报内存溢出

EasyExcel大数据量导出常见方法

1. 分批写入
  • EasyExcel支持分批写入数据,可以将数据分批加载到内存中,分批写入Excel文件,避免一次性将大量数据加载到内存中。

  • 示例代码

    String fileName = "large_data.xlsx";ExcelWriter excelWriter = EasyExcel.write(fileName).build();WriteSheet writeSheet = EasyExcel.writerSheet("Sheet1").build();// 假设每次写入10000条数据int batchSize = 10000;List<Data> dataList;int pageIndex = 0;do {// 分页获取数据dataList = getDataByPage(pageIndex++, batchSize);excelWriter.write(dataList, writeSheet);} while (dataList.size() == batchSize);// 关闭资源excelWriter.finish();
    
2. 设置合适的JVM内存
  • 针对大数据导出场景,可以尝试增大JVM的内存分配,例如:

    java -Xms512M -Xmx4G -jar yourApp.jar
    
  • 解释

    • -Xms512M:设置初始堆大小为512MB。
    • -Xmx4G:设置最大堆大小为4GB。
3. 减少数据对象的复杂性
  • 导出数据时,尽量简化数据对象,避免不必要的嵌套和多余字段的加载,以减少对象占用的内存空间。
4. 关闭自动列宽设置
  • EasyExcel的自动列宽功能会占用大量内存,特别是在数据量较大的情况下。关闭自动列宽可以节省内存。

  • 示例代码

    EasyExcel.write(fileName).registerWriteHandler(new SimpleWriteHandler()) // 不使用自动列宽.sheet("Sheet1").doWrite(dataList);
    
5. 使用Stream导出(适合大数据)
  • 利用OutputStream分批写入数据,减少内存消耗。通过BufferedOutputStream可以进一步提高性能。

  • 示例代码

    try (OutputStream out = new BufferedOutputStream(new FileOutputStream(fileName))) {ExcelWriter excelWriter = EasyExcel.write(out).build();WriteSheet writeSheet = EasyExcel.writerSheet("Sheet1").build();int pageIndex = 0;List<Data> dataList;do {dataList = getDataByPage(pageIndex++, batchSize);excelWriter.write(dataList, writeSheet);} while (dataList.size() == batchSize);excelWriter.finish();} catch (IOException e) {e.printStackTrace();}
    
6. 选择合适的数据导出工具
  • 如果数据量非常大,可以考虑切换到支持更高性能的导出工具(如Apache POI的SXSSFWorkbook),适合导出百万级别数据量,但配置和使用会更复杂。

亮点来了,那要如何使用 POI 的 SXSSFWorkbook来导出百万级别的数据量呢?

Apache POI的SXSSFWorkbook 实现百万级别数据量的导出案例

使用Apache POI的SXSSFWorkbook可以处理大数据量的Excel导出,因为SXSSFWorkbook基于流式写入,不会将所有数据加载到内存中,而是使用临时文件进行缓存,这样可以显著减少内存消耗,适合百万级别数据的导出。下面我们来看一个完整的实现示例。

代码如下
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;public class LargeDataExportExample {public static void main(String[] args) {// 文件输出路径String filePath = "vg_large_data_export.xlsx";// 导出百万级数据exportLargeData(filePath);}private static void exportLargeData(String filePath) {// 每次写入的批次大小final int batchSize = 10000;// 数据总条数final int totalRows = 1_000_000;// 创建SXSSFWorkbook对象,内存中只保留100行,超过的部分会写入临时文件SXSSFWorkbook workbook = new SXSSFWorkbook(100);workbook.setCompressTempFiles(true); // 启用临时文件压缩// 创建工作表Sheet sheet = workbook.createSheet("Large Data");// 创建标题行Row headerRow = sheet.createRow(0);String[] headers = {"ID", "Name", "Age"};for (int i = 0; i < headers.length; i++) {Cell cell = headerRow.createCell(i);cell.setCellValue(headers[i]);}int rowNum = 1; // 数据开始的行号try {// 按批次写入数据for (int i = 0; i < totalRows / batchSize; i++) {// 模拟获取每批数据List<Data> dataList = getDataBatch(rowNum, batchSize);// 将数据写入到Excel中for (Data data : dataList) {Row row = sheet.createRow(rowNum++);row.createCell(0).setCellValue(data.getId());row.createCell(1).setCellValue(data.getName());row.createCell(2).setCellValue(data.getAge());}// 处理完成一批数据后,可以选择清除缓存数据,防止内存溢出((SXSSFSheet) sheet).flushRows(batchSize); // 清除已写的行缓存}// 将数据写入文件try (FileOutputStream fos = new FileOutputStream(filePath)) {workbook.write(fos);}System.out.println("数据导出完成:" + filePath);} catch (IOException e) {e.printStackTrace();} finally {// 关闭workbook并删除临时文件workbook.dispose();}}/*** 模拟分页获取数据*/private static List<Data> getDataBatch(int startId, int batchSize) {List<Data> dataList = new ArrayList<>(batchSize);for (int i = 0; i < batchSize; i++) {dataList.add(new Data(startId + i, "Name" + (startId + i), 20 + (startId + i) % 50));}return dataList;}// 数据类static class Data {private final int id;private final String name;private final int age;public Data(int id, String name, int age) {this.id = id;this.name = name;this.age = age;}public int getId() {return id;}public String getName() {return name;}public int getAge() {return age;}}
}
来解释一下代码
  1. SXSSFWorkbookSXSSFWorkbook(100)表示内存中最多保留100行数据,超过的部分会写入临时文件,节省内存。
  2. 批次处理:通过batchSize控制每批次写入的数据量,以减少内存消耗。totalRows设置为1,000,000表示导出100万条数据。
  3. 模拟数据生成getDataBatch方法模拟分页获取数据,每次返回一批数据。
  4. 清除缓存行:每次写入一批数据后,通过flushRows(batchSize)将缓存的行从内存中清除,以控制内存占用。
  5. 压缩临时文件workbook.setCompressTempFiles(true)启用临时文件压缩,进一步减少磁盘空间占用。

需要注意的事项

  • 临时文件:SXSSFWorkbook会在系统临时文件夹中生成临时文件,需要确保磁盘空间足够。
  • 资源释放:完成数据写入后需要调用workbook.dispose()以清理临时文件。
  • 性能优化:可根据机器内存调整batchSizeSXSSFWorkbook缓存行数,避免频繁刷新和内存溢出。

作为程序员,持续学习和充电非常重要,作为开发者,我们需要保持好奇心和学习热情,不断探索新的技术,只有这样,我们才能在这个快速发展的时代中立于不败之地。低代码也是一个值得我们深入探索的领域,让我们拭目以待,它将给前端世界带来怎样的变革,推荐一个低代码工具。

应用地址:www.jnpfsoft.com
开发语言:Java/.net

这是一个基于Flowable引擎(支持java、.NET),已支持MySQL、SqlServer、Oracle、PostgreSQL、DM(达梦)、 KingbaseES(人大金仓)6个数据库,支持私有化部署,前后端封装了上千个常用类,方便扩展,框架集成了表单、报表、图表、大屏等各种常用的 Demo 方便直接使用。

至少包含表单建模、流程设计、报表可视化、代码生成器、系统管理、前端 UI 等组件,这种情况下我们避免了重复造轮子,已内置大量的成熟组件,选择合适的组件进行集成或二次开发复杂功能,即可自主开发一个属于自己的应用系统。

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

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

相关文章

Qt 的事件投递机制:从基础到实战

在 Qt 开发中&#xff0c;事件系统是核心概念之一&#xff0c;几乎每一个 GUI 应用程序都依赖于它来响应用户操作和系统通知。对于有一定 Qt 基础但首次接触事件投递 (QCoreApplication::postEvent) 的开发者而言&#xff0c;理解事件投递机制尤为重要。这篇博客将带你从基本概…

QDialog中,reject()和close()区别

1. reject()函数 reject()是QDialog类中的一个槽函数&#xff0c;用于以“拒绝”的方式关闭对话框。它通常与对话框的“取消”操作相关联。当调用reject()时&#xff0c;会发出rejected()信号。 行为细节&#xff1a; 从模态对话框的角度来看&#xff0c;当模态对话框调用reje…

【036】基于51单片机五子棋游戏机【Proteus仿真+Keil程序+报告+原理图】

☆、设计硬件组成&#xff1a;51单片机最小系统LCD12864液晶显示按键控制。 1、设计采用STC89C51/52、AT89C51/52、AT89S51/52作为主控芯片&#xff0c;采用LCD12864液晶作为显示&#xff1b; 2、游戏有 人机对战 和 玩家对战 两种模式&#xff0c;玩家白子先下&#xff1b; …

HTML通过JavaScript获取访问连接,IP和端口

<!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <title>Get IP Address</title> <script> function displayURL() { var url window.location.href; // 获取当…

VMWARE虚拟交换机的负载平衡算法

一、基于源虚拟端口的路由 虚拟交换机可根据 vSphere 标准交换机或 vSphere Distributed Switch 上的虚拟机端口 ID 选择上行链路。 基于源虚拟端口的路由是 vSphere 标准交换机和 vSphere Distributed Switch 上的默认负载平衡方法。 ESXi主机上运行的每个虚拟机在虚拟交换…

slam里的体素滤波

SLAM系统通常需要处理大量的传感器数据&#xff0c;如激光雷达&#xff08;LiDAR&#xff09;、相机等获取的数据&#xff0c;这些数据往往包含了大量的冗余信息和噪声。为了提高SLAM系统的效率和准确性&#xff0c;数据预处理是非常重要的一步&#xff0c;体素滤波就是一种常用…

web——sqliabs靶场——第十二关——(基于错误的双引号 POST 型字符型变形的注入)

判断注入类型 a OR 1 1# 发现没有报错 &#xff0c;说明单引号不是闭合类型 测试别的注入条件 a) OR 1 1# a)) OR 1 1# a" OR 11 发现可以用双引号闭合 发现是")闭合 之后的流程还是与11关一样 爆破显示位 先抓包 是post传参&#xff0c;用hackbar来传参 unam…

AI时代,百度的三大主义

现实主义、长期主义、理想主义。 定焦One&#xff08;dingjiaoone&#xff09;原创 作者 | 苏琦 郑浩钧 编辑 | 魏佳 “人工智能很像是一次新的工业革命&#xff0c;这意味着它不会三五年就结束&#xff0c;也不会一两年就出现‘超级应用’&#xff0c;它更像是三五十年对于整…

C++基础入门篇

C入门 第一个C程序 首先C兼容c语言&#xff0c;所以由c语言实现的内容仍然可以在C中实现&#xff0c;但是c语言的文件后缀是.c但是C的后缀是.cpp。vs对于cpp文件使用C编译器编译&#xff0c;linux需要用g编译而不是gcc #include<stdio> int main() {printf("hello…

基于YOLOv11的火焰实时检测系统(python+pyside6界面+系统源码+可训练的数据集+也完成的训练模型)

100多种【基于YOLOv8/v10/v11的目标检测系统】目录&#xff08;pythonpyside6界面系统源码可训练的数据集也完成的训练模型 摘要&#xff1a; 本文提出了一种基于YOLOv11算法的火灾检测系统&#xff0c;利用1852张图片&#xff08;1647张训练集&#xff0c;205张验证集&#…

Python入门(10)--面向对象进阶

Python面向对象进阶 &#x1f680; 1. 继承与多态 &#x1f504; 1.1 继承基础 class Animal:def __init__(self, name, age):self.name nameself.age agedef speak(self):passdef describe(self):return f"{self.name} is {self.age} years old"class Dog(Anim…

算法——两两交换链表中的节点(leetcode24)

这是一道对于链表节点进行操作的题目非常考验对于链表操作的基本功&#xff1b; 解法: 本题的解法结合下图来进一步解释 创建一个虚拟节点指向头结点以便使代码逻辑看起来更为简便且操作节点容易,定义cur是为了方便找到cur之后的两个节点进行交换操作定义pre和aft是为了保存执…

【提效工具开发】管理Python脚本执行系统实现页面展示

Python脚本执行&#xff1a;工具管理Python脚本执行系统 背景 在现代的软件开发和测试过程中&#xff0c;自动化工具和脚本的管理变得至关重要。为了更高效地管理工具、关联文件、提取执行参数并支持动态执行Python代码&#xff0c;我们设计并实现了一套基于Django框架的工具…

鸿蒙开发:ForEach中为什么键值生成函数很重要

前言 在列表组件使用的时候&#xff0c;如List、Grid、WaterFlow等&#xff0c;循环渲染时都会使用到ForEach或者LazyForEach&#xff0c;当然了&#xff0c;也有单独使用的场景&#xff0c;如下&#xff0c;一个很简单的列表组件使用&#xff0c;这种使用方式&#xff0c;在官…

Figma插件指南:12款提升设计生产力的插件

在当今的设计领域&#xff0c;Figma已经成为许多UI设计师和团队的首选原型和数字设计软件。随着Figma的不断更新和插件库的扩展&#xff0c;这些工具极大地提升了设计工作的效率。本文将介绍12款实用的Figma插件&#xff0c;帮助你在UI设计中更加高效。 即时AI 即时AI利用先进…

揭秘云计算 | 5、关于云计算效率的讨论

一、 公有云效率更高&#xff1f; 解&#xff1a;公有云具有更高的效率。首先我们需要知道效率到底指的是什么。这是个亟须澄清的概念。在这里效率是指云数据中心&#xff08;我们将在后文中介绍其定义&#xff09;中的IT设备资源利用率&#xff0c;其中最具有代表性的指标就是…

Spring Boot 和 Spring Cloud 构建一个完整的微服务架构——在线购物系统

接上一篇博客&#xff0c;大家可以结合一起看看实例理解https://blog.csdn.net/speaking_me/article/details/143917383?spm1001.2014.3001.5502 构建一个综合性的大型微服务项目可以帮助开发者更全面地理解和掌握 Spring Boot 和 Spring Cloud 的应用。 接下来&#xff0c;…

Flutter:AnimatedPadding动态修改padding

// 默认top为10&#xff0c;点击后修改为100&#xff0c;此时方块会向下移动 padding: EdgeInsets.fromLTRB(left, top, right, bottom),class _MyHomePageState extends State<MyHomePage> {bool flag true;overrideWidget build(BuildContext context) {return Scaffo…

【c++丨STL】stack和queue的使用及模拟实现

&#x1f31f;&#x1f31f;作者主页&#xff1a;ephemerals__ &#x1f31f;&#x1f31f;所属专栏&#xff1a;C、STL 目录 前言 一、什么是容器适配器 二、stack的使用及模拟实现 1. stack的使用 empty size top push和pop swap 2. stack的模拟实现 三、queue的…

JavaEE初学07

JavaEE初学07 MybatisORMMybatis一对一结果映射一对多结果映射 Mybatis动态sqlif标签trim标签where标签set标签foreach标签补充 在这里插入图片描述右击运行即可 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/c71d44d027374a399d5d537ce96f00e1.png) Mybatis Myba…