当前位置: 代码网 > it编程>编程语言>Java > Java EasyExcel导出报内存溢出的解决办法

Java EasyExcel导出报内存溢出的解决办法

2024年10月28日 Java 我要评论
easyexcel大数据量导出常见方法1. 分批写入easyexcel支持分批写入数据,可以将数据分批加载到内存中,分批写入excel文件,避免一次性将大量数据加载到内存中。示例代码: str

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;
        }
    }
}

来解释一下代码

  • sxssfworkbooksxssfworkbook(100)表示内存中最多保留100行数据,超过的部分会写入临时文件,节省内存。
  • 批次处理:通过batchsize控制每批次写入的数据量,以减少内存消耗。totalrows设置为1,000,000表示导出100万条数据。
  • 模拟数据生成getdatabatch方法模拟分页获取数据,每次返回一批数据。
  • 清除缓存行:每次写入一批数据后,通过flushrows(batchsize)将缓存的行从内存中清除,以控制内存占用。
  • 压缩临时文件workbook.setcompresstempfiles(true)启用临时文件压缩,进一步减少磁盘空间占用。

需要注意的事项

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

以上就是java easyexcel导出报内存溢出的解决办法的详细内容,更多关于java easyexcel导出内存溢出的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com