ToB企服应用市场:ToB评测及商务社交产业平台

标题: Java EasyExcel 导出报内存溢出如何解决 [打印本页]

作者: 去皮卡多    时间: 2024-10-28 14:10
标题: Java EasyExcel 导出报内存溢出如何解决
各人好,我是 V 哥。使用EasyExcel举行大数据量导出时轻易导致内存溢出,特别是在导出百万级别的数据时。你有碰到过这种情况吗,以下是V 哥整理的解决该问题的一些常见方法,分享给各人,接待一起讨论:
EasyExcel大数据量导出常见方法

1. 分批写入

  1.      String fileName = "large_data.xlsx";
  2.      ExcelWriter excelWriter = EasyExcel.write(fileName).build();
  3.      WriteSheet writeSheet = EasyExcel.writerSheet("Sheet1").build();
  4.      // 假设每次写入10000条数据
  5.      int batchSize = 10000;
  6.      List<Data> dataList;
  7.      int pageIndex = 0;
  8.      do {
  9.          // 分页获取数据
  10.          dataList = getDataByPage(pageIndex++, batchSize);
  11.          excelWriter.write(dataList, writeSheet);
  12.      } while (dataList.size() == batchSize);
  13.      // 关闭资源
  14.      excelWriter.finish();
复制代码
2. 设置合适的JVM内存

  1.      java -Xms512M -Xmx4G -jar yourApp.jar
复制代码
3. 淘汰数据对象的复杂性

4. 关闭自动列宽设置

  1.      EasyExcel.write(fileName)
  2.              .registerWriteHandler(new SimpleWriteHandler()) // 不使用自动列宽
  3.              .sheet("Sheet1")
  4.              .doWrite(dataList);
复制代码
5. 使用Stream导出(适合大数据)

  1.      try (OutputStream out = new BufferedOutputStream(new FileOutputStream(fileName))) {
  2.          ExcelWriter excelWriter = EasyExcel.write(out).build();
  3.          WriteSheet writeSheet = EasyExcel.writerSheet("Sheet1").build();
  4.          int pageIndex = 0;
  5.          List<Data> dataList;
  6.          do {
  7.              dataList = getDataByPage(pageIndex++, batchSize);
  8.              excelWriter.write(dataList, writeSheet);
  9.          } while (dataList.size() == batchSize);
  10.          excelWriter.finish();
  11.      } catch (IOException e) {
  12.          e.printStackTrace();
  13.      }
复制代码
6. 选择合适的数据导出工具

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

使用Apache POI的SXSSFWorkbook可以处理大数据量的Excel导出,因为SXSSFWorkbook基于流式写入,不会将所有数据加载到内存中,而是使用暂时文件举行缓存,这样可以显著淘汰内存斲丧,适合百万级别数据的导出。下面我们来看一个完整的实现示例。
代码如下
  1. import org.apache.poi.ss.usermodel.*;
  2. import org.apache.poi.xssf.streaming.SXSSFWorkbook;
  3. import java.io.FileOutputStream;
  4. import java.io.IOException;
  5. import java.util.ArrayList;
  6. import java.util.List;
  7. public class LargeDataExportExample {
  8.     public static void main(String[] args) {
  9.         // 文件输出路径
  10.         String filePath = "vg_large_data_export.xlsx";
  11.         
  12.         // 导出百万级数据
  13.         exportLargeData(filePath);
  14.     }
  15.     private static void exportLargeData(String filePath) {
  16.         // 每次写入的批次大小
  17.         final int batchSize = 10000;
  18.         // 数据总条数
  19.         final int totalRows = 1_000_000;
  20.         // 创建SXSSFWorkbook对象,内存中只保留100行,超过的部分会写入临时文件
  21.         SXSSFWorkbook workbook = new SXSSFWorkbook(100);
  22.         workbook.setCompressTempFiles(true); // 启用临时文件压缩
  23.         // 创建工作表
  24.         Sheet sheet = workbook.createSheet("Large Data");
  25.         // 创建标题行
  26.         Row headerRow = sheet.createRow(0);
  27.         String[] headers = {"ID", "Name", "Age"};
  28.         for (int i = 0; i < headers.length; i++) {
  29.             Cell cell = headerRow.createCell(i);
  30.             cell.setCellValue(headers[i]);
  31.         }
  32.         int rowNum = 1; // 数据开始的行号
  33.         try {
  34.             // 按批次写入数据
  35.             for (int i = 0; i < totalRows / batchSize; i++) {
  36.                 // 模拟获取每批数据
  37.                 List<Data> dataList = getDataBatch(rowNum, batchSize);
  38.                
  39.                 // 将数据写入到Excel中
  40.                 for (Data data : dataList) {
  41.                     Row row = sheet.createRow(rowNum++);
  42.                     row.createCell(0).setCellValue(data.getId());
  43.                     row.createCell(1).setCellValue(data.getName());
  44.                     row.createCell(2).setCellValue(data.getAge());
  45.                 }
  46.                 // 处理完成一批数据后,可以选择清除缓存数据,防止内存溢出
  47.                 ((SXSSFSheet) sheet).flushRows(batchSize); // 清除已写的行缓存
  48.             }
  49.             // 将数据写入文件
  50.             try (FileOutputStream fos = new FileOutputStream(filePath)) {
  51.                 workbook.write(fos);
  52.             }
  53.             System.out.println("数据导出完成:" + filePath);
  54.         } catch (IOException e) {
  55.             e.printStackTrace();
  56.         } finally {
  57.             // 关闭workbook并删除临时文件
  58.             workbook.dispose();
  59.         }
  60.     }
  61.     /**
  62.      * 模拟分页获取数据
  63.      */
  64.     private static List<Data> getDataBatch(int startId, int batchSize) {
  65.         List<Data> dataList = new ArrayList<>(batchSize);
  66.         for (int i = 0; i < batchSize; i++) {
  67.             dataList.add(new Data(startId + i, "Name" + (startId + i), 20 + (startId + i) % 50));
  68.         }
  69.         return dataList;
  70.     }
  71.     // 数据类
  72.     static class Data {
  73.         private final int id;
  74.         private final String name;
  75.         private final int age;
  76.         public Data(int id, String name, int age) {
  77.             this.id = id;
  78.             this.name = name;
  79.             this.age = age;
  80.         }
  81.         public int getId() {
  82.             return id;
  83.         }
  84.         public String getName() {
  85.             return name;
  86.         }
  87.         public int getAge() {
  88.             return age;
  89.         }
  90.     }
  91. }
复制代码
来解释一下代码

需要注意的事项

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4