当前位置: 首页 > news >正文

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

大家好,我是 V 哥。使用EasyExcel进行大数据量导出时容易导致内存溢出,特别是在导出百万级别的数据时。你有遇到过这种情况吗,以下是V 哥整理的解决该问题的一些常见方法,分享给大家,欢迎一起讨论:
V 哥推荐:2024 最适合入门的 JAVA 课程

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缓存行数,避免频繁刷新和内存溢出。

http://www.mrgr.cn/news/63391.html

相关文章:

  • 2024年广东省工科大学生实验综合技能竞赛——越障救援机器
  • 怎么申请号码认证显示公司名?
  • WPF+Mvvm案例实战(五)- 自定义雷达图实现
  • 漏洞分析技术实践_数组越界漏洞
  • openpnp - 在openpnp中单独测试相机
  • C++11之列表初始化
  • WSGI、uwsgi、uWSGI与Nginx
  • sqoop问题汇总记录
  • <实用干货>临床试验数据信息查询--中国临床试验数据库
  • 牛客网最新Java高频面试题汇总(2024最新含答案)
  • Rust 力扣 - 189. 轮转数组
  • ^M 字符处理
  • GaussDB Ustore存储引擎解读
  • Google Play商店中的类似应用:它们对ASO优化重要吗?
  • go-zero 的使用
  • 探索医学数据:使用Seaborn的成对关系图揭示变量间的关联
  • Leetcode 62. 不同路径 动态规划+空间优化
  • 【文本情感分析识别】Python+SVM算法+模型训练+文本分类+文本情感分析
  • vxe-table v4.8+ 与 v3.10+ 虚拟滚动支持动态行高,虚拟渲染更快了
  • 低代码技术:加速企业数字化转型的利器
  • 河南高校大数据实验室建设案例分享
  • 第十九章 特殊工具与技术
  • 10 P1094 [NOIP2007 普及组] 纪念品分组
  • Nginx 文件名逻辑漏洞(CVE-2013-4547)
  • ctfshow--xss靶场web327-web333(一命速通不了的靶场)
  • 法律文件智能识别:免费OCR平台优化数字化管理