一文带你彻底玩转EasyExcel:导入导出excel数据起飞

原创 Shepherd Shepherd进阶笔记 2024-04-18 08:40 浙江

Shepherd进阶笔记

专注分享Java技术进阶知识点,日常工作点点滴滴,滴水穿石

58篇原创内容

公众号

1.简介

在日常的开发工作中,Excel 文件的读取和写入是非常常见的需求,特别是在后台管理系统中更为频繁,基于传统的方式操作excel通常比较繁琐,EasyExcel 库的出现为我们带来了更简单、更高效的解决方案。本文将介绍 EasyExcel 库的基本用法和一些常见应用场景,帮助开发者更好地利用 EasyExcel 提高工作效率。官网地址:https://github.com/alibaba/easyexcel

青出于蓝而胜于蓝

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

16M内存23秒读取75M(46W行25列)的Excel(3.2.1+版本)

当然还有极速模式能更快,但是内存占用会在100M多一点 !

图片

EasyExcel 的核心类主要包括以下几个:

  1. ExcelReader: 用于读取 Excel 文件的核心类。通过 ExcelReader 类可以读取 Excel 文件中的数据,并进行相应的处理和操作。

  2. ExcelWriter: 用于写入 Excel 文件的核心类。通过 ExcelWriter 类可以将数据写入到 Excel 文件中,并进行样式设置、标题添加等操作。

  3. AnalysisEventListener: 事件监听器接口,用于处理 Excel 文件读取过程中的事件,如读取到每一行数据时的操作。

  4. AnalysisContext: 读取 Excel 文件时的上下文信息,包括当前行号、sheet 名称等。通过 AnalysisContext 可以获取到读取过程中的一些关键信息。

  5. WriteHandler: 写入 Excel 文件时的处理器接口,用于处理 Excel 文件的样式设置、标题添加等操作。

  6. WriteSheet: 写入 Excel 文件时的 Sheet 配置类,用于指定写入数据的 Sheet 名称、样式等信息。

这些核心类在 EasyExcel 中承担了不同的角色,协作完成了 Excel 文件的读取和写入操作。开发者可以根据具体的需求和场景,使用这些类来实现 Excel 文件的各种操作。

Alibaba EasyExcel的核心入口类是EasyExcel类,就想我们平时封装的Util类一样,通过它对excel数据读取或者导出。

2.EasyExcel数据导入

2.1.简单导入

准备excel数据文件

这里以用户信息数据为例

图片

定义用户信息User类

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public class User {

    private Long id;

    private String userNo;

    private String name;

    private Integer gender;

    private Date birthday;

    private String phone;

    private String email;

    @ExcelIgnore
    private Integer isDelete;

    private String address;


}

事件监听器ReadListener

图片

我们一般使用EasyExcel 的 AnalysisEventListener,用于监听 Excel 文件读取事件的接口,通过实现这个接口,可以在读取 Excel 文件的过程中对数据进行处理和操作:

/**
 * @author fjzheng
 * @version 1.0
 * @date 2024/4/12 16:22
 */
@Slf4j
public class UserExcelListener extends AnalysisEventListener<User> {

    /**
     * 每隔100条处理下,然后清理list ,方便内存回收
     */
    private static final int BATCH_COUNT = 100;


    /**
     * 缓存的数据
     */
    private List<User> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);


    /**
     *
     * @param exception
     * @param context
     * @throws Exception
     */
    @Override
    public void onException(Exception exception, AnalysisContext context) throws Exception {
        log.error("======>>>解析异常:", exception);
        throw exception;
    }

    /**
     * 当读取到一行数据时,会调用这个方法,并将读取到的数据以及上下文信息作为参数传入
     * 可以在这个方法中对读取到的数据进行处理和操作,处理数据时要注意异常错误,保证读取数据的稳定性
     * @param user
     * @param context
     */
    @Override
    public void invoke(User user, AnalysisContext context) {
        log.info("解析到一条数据:{}", user);
        cachedDataList.add(user);
        if (cachedDataList.size() >= BATCH_COUNT) {
            // 处理缓存的数据,比如说入库。。。
            // 然后清空
            cachedDataList.clear();
        }
    }

    /**
     * 当每个sheet所有数据读取完毕后,会调用这个方法,可以在这个方法中进行一些收尾工作,如资源释放、数据汇总等。
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 收尾工作,处理剩下的缓存数据。。。

        log.info("sheet={} 所有数据解析完成!", context.readSheetHolder().getSheetName());
    }

}

注意 UserExcelListener 不能被Spring管理,要每次读取excel都要new一个新的监听器,如果里面用到spring bean,可以通过构造方法传进去

执行测试用例

/**
 * @author fjzheng
 * @version 1.0
 * @date 2024/4/11 18:04
 */
@SpringBootTest
@RunWith(SpringRunner.class)
@Slf4j
public class ExcelTest {

    @Test
    public void testExcelRead() {
        String fileName = "/Users/shepherdmy/Desktop/test1.xlsx";
        EasyExcel.read(fileName, User.class, new UserExcelListener()).sheet().doRead();
        // 如果excel是多行表头比如说2行,需要设置行头数headRowNumber,默认不设置为1行表头,sheet不传默认读取第一个sheet
//        EasyExcel.read(fileName, User.class, new UserExcelListener()).sheet().headRowNumber(2).doRead();
    }
}

执行结果控制台输出如下:

解析到一条数据:User(id=1, userNo=she001, name=王小二, gender=0, birthday=Fri Apr 12 10:00:00 CST 2024, phone=123456789, email=123456789@126.com, isDelete=null, address=杭州市余杭区未来科技城)
解析到一条数据:User(id=2, userNo=she002, name=张三, gender=1, birthday=Wed Apr 10 18:00:00 CST 2024, phone=987654321, email=123456789@qq.com, isDelete=null, address=杭州市拱墅区城西银泰)
解析到一条数据:User(id=3, userNo=she003, name=李四, gender=1, birthday=Thu Apr 11 18:00:00 CST 2024, phone=345686789, email=23445654@163.com, isDelete=null, address=上海陆家嘴浦东)
sheet=用户信息 所有数据解析完成!

完美解析导入,你是否注意到上面我们定义User类的属性和excel文件的字段一一对应,顺序高度一致,如果顺序映射不一致,比如说定义的时候把姓名name和性别gender的字段顺序调换,会导致导入解析字符串类型转整数失败,这是因为在 EasyExcel 中,当导入数据时,默认情况下是按照 Excel 表格中列的顺序来映射数据的。也就是说,如果 Excel 表格的第一列对应 Java 对象的第一个属性,第二列对应第二个属性,以此类推。

在源码层面,EasyExcel 是通过反射机制来实现数据的映射的。具体来说,EasyExcel 在读取 Excel 文件时,会根据 Java 对象的属性顺序和 Excel 表格中列的顺序来一一对应。这个过程是在 EasyExcel 内部进行的,开发者不需要关心具体的实现细节,只需要提供正确的 Java 对象结构和 Excel 表格格式即可。

项目推荐:基于SpringBoot2.x、SpringCloud和SpringCloudAlibaba企业级系统架构底层框架封装,解决业务开发时常见的非功能性需求,防止重复造轮子,方便业务快速开发和企业技术栈框架统一管理。引入组件化的思想实现高内聚低耦合并且高度可配置化,做到可插拔。严格控制包依赖和统一版本管理,做到最少化依赖。注重代码规范和注释,非常适合个人学习和企业使用

Github地址:https://github.com/plasticene/plasticene-boot-starter-parent

Gitee地址:https://gitee.com/plasticene3/plasticene-boot-starter-parent

微信公众号Shepherd进阶笔记

交流探讨qun:Shepherd_126

2.2 EasyExcel提供的注解

上面User类的定义使用了注解@ExcelIgnore,表示字段isDelete不参与数据映射,要不然严格按照顺序就会把excel的地址列映射给isDelete导致字符串转整数类型转换错误了。

EasyExcel 提供了一些注解,用于帮助开发者更灵活地控制 Excel 文件的读取和写入操作。以下是 EasyExcel 中常用的注解:

@ExcelProperty

@ExcelProperty 注解用于标注 Java 对象中的属性与 Excel 表格中的列的对应关系。该注解包含以下属性:

  • value:指定 Excel 表格中的列索引,表示该属性对应的列在 Excel 表格中的位置。支持字符串形式(如 "A"、"B"、"C")和数字形式(从 0 开始)。

  • index:同 value,用于指定 Excel 表格中的列索引。

  • index 和 value 二选一即可,用于指定 Excel 表格中的列索引。

示例:

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "tb_user")
public class User {

    @TableId(type = IdType.AUTO)
    @ExcelProperty(index = 0)
    private Long id;
    @ExcelProperty(index = 1)
    private String userNo;
    @ExcelProperty(index = 3)
//    @ExcelProperty("性别")
    private Integer gender;
    @ExcelProperty(index = 2)
//    @ExcelProperty("姓名")
    private String name;
    @ExcelProperty(index = 4)
    private Date birthday;
    @ExcelProperty(index = 5)
    private String phone;
    @ExcelProperty(index = 6)
    private String email;
//    @ExcelIgnore
    private Integer isDelete;
    @ExcelProperty(index = 7)
    private String address;
}

一开始我们定义User类时并没有使用@ExcelProperty(),但其实等价于按照类属性顺序从0开始加上了@ExcelProperty(index =列顺序号),注意我特意把字段属性姓名name和性别gender调换了顺序,但是index是按照excel来写的,同时我去掉了isDelete的忽略属性@ExcelIgnore。正常解析导入。。。

在我们日常开发过程中,我个人建议在excel映射的类上必须使用@ExcelProperty()注解标注,至于使用@ExcelProperty(index = 2)还是@ExcelProperty("姓名")都可以,但不能同时用,我个人倾向于@ExcelProperty("姓名"),这样可以备注字段含义,当然一般人不太会修改excel表头的字段,但是很有可能因为显示查看会拖动excel列的顺序这样就会导致@ExcelProperty(index =列顺序号)映射出错。

@ExcelIgnore

@ExcelIgnore 注解用于标注 Java 对象中的属性,表示在 Excel 文件的读取和写入过程中忽略该属性。示例如上描述

@ExcelIgnoreUnannotated

@ExcelIgnoreUnannotated 注解用于指定在读取 Excel 文件时是否忽略未标注 @ExcelProperty 注解的属性,默认为 false,即不忽略。上面我们去掉了isDelete的@ExcelIgnore能正常导出那是因为我们excel文件只有8列刚刚好够标注了@ExcelProperty映射,加入我们excel文件在添加一列,就会去映射isDelete,不符合我们预期,这时候我们就需要在类使用**@ExcelIgnoreUnannotated**解决此问题

@ExcelSheet

@ExcelSheet 注解用于指定读取 Excel 文件时的 Sheet 名称。通常用于读取多个 Sheet 的情况。

@ExcelIgnoreRowNum

@ExcelIgnoreRowNum 注解用于标注 Java 对象中的属性,表示在 Excel 文件的读取过程中忽略行号。通常用于读取时不需要关注行号的情况。

@ColumnWidth

@ColumnWidth主要是控制列宽

2.1.3 日期、数字或者自定义格式转换

数据转换我们只需要实现easyexcel封装的Converter接口即可,比如在上面的用户信息类User的学号属性userNo统一在excel的值加上前缀uno:, 性别属性gender由字符串转枚举值男:0 女:1 未知:2

UserNoConverter

public class UserNoConverter implements Converter<String> {

    /**
     * 支持的java类型
     * @return
     */
    @Override
    public Class<?> supportJavaTypeKey() {
        return String.class;
    }

    /**
     * 支持的excel值类型
     * @return
     */
    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    /**
     * 这里读的时候会调用
     *
     * @param context
     * @return
     */
    @Override
    public String convertToJavaData(ReadConverterContext<?> context) {
        return "uno:" + context.getReadCellData().getStringValue();
    }

    /**
     * 这里是写的时候会调用 不用管
     *
     * @return
     */
    @Override
    public WriteCellData<?> convertToExcelData(WriteConverterContext<String> context) {
        return new WriteCellData<>(context.getValue());
    }
}

GenderConverter

public class GenderConverter implements Converter<Integer> {

    @Override
    public Class<?> supportJavaTypeKey() {
        return Integer.class;
    }

    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    /**
     * 从excel读数据时候调用
     * @param cellData
     * @param contentProperty
     * @param globalConfiguration
     * @return
     */
    @Override
    public Integer convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty,
                                     GlobalConfiguration globalConfiguration) {
        String value = cellData.getStringValue();
        if (StringUtils.isBlank(value)){
            // 未知
            return 2;
        }
        if (value.indexOf('男') != -1) {
            return 0;
        }
        if (value.indexOf('女') != -1) {
            return 1;
        }
        return 2;
    }

    /**
     * 写数据到excel里面
     * @param context
     * @return
     */
    @Override
    public WriteCellData<?> convertToExcelData(WriteConverterContext<Integer> context) {
        Integer value = context.getValue();
        if (Objects.equals(value, 0)) {
           return new WriteCellData<>("男");
        }
        if (Objects.equals(value, 1)) {
            return new WriteCellData<>("女");
        }
        return new WriteCellData<>("未知");
    }
}

在映射的实体类User进行转换器绑定:

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
// @ExcelIgnoreUnannotated
public class User {

    @ExcelProperty(index = 0)
    private Long id;
    @ExcelProperty(index = 1, converter = UserNoConverter.class)
    private String userNo;
    @ExcelProperty(index = 3, converter = GenderConverter.class)
//    @ExcelProperty("性别")
    private Integer gender;
    @ExcelProperty(index = 2)
//    @ExcelProperty("姓名")
    private String name;
    @ExcelProperty(index = 4)
    private Date birthday;
    @ExcelProperty(index = 5)
    private String phone;
    @ExcelProperty(index = 6)
    private String email;
    @ExcelIgnore
    private Integer isDelete;
    @ExcelProperty(index = 7)
    private String address;
}

图片

执行结果:

图片

2.1.4 读取多个sheet

我们前面用户信息基础再加了一个sheet2接着存用户信息,同时新增一个sheet=银行信息存储银行账户信息:

图片

银行账号信息类:

@Data
public class Account {
    private String name;
    private String idCard;
    private String cardNo;
    private BigDecimal amount;
    private Integer status;
    private Date lastUsedTime;
}

如果我们没有银行信息这个sheet,我们可以用如下代码读写所有sheet:因为每个sheet的数据格式是一样的

        // 读取所有sheet
        EasyExcel.read(fileName, User.class, new UserExcelListener()).doReadAll();

每个sheet的数据格式不一样,只能单独一一处理,新建一个处理银行账号信息的监听器:

@Slf4j
public class AccountExcelListener extends AnalysisEventListener<Account> {
    @Override
    public void onException(Exception exception, AnalysisContext context) throws Exception {
        log.error("======>>>解析异常:", exception);
    }

    @Override
    public void invoke(Account data, AnalysisContext context) {
        log.info("解析到一条数据:{}", data);
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        log.info("sheet={} 所有数据解析完成!", context.readSheetHolder().getSheetName());
    }
  
      /**
     * 解析表头数据
     * @param headMap
     * @param context
     */
    @Override
    public void invokeHead(Map<Integer, ReadCellData<?>> headMap, AnalysisContext context) {
       log.info("表头数据:{}", ConverterUtils.convertToStringMap(headMap, context));
    }
}

测试用例方法改为如下:

    @Test
    public void testExcelRead() {
        String fileName = "/Users/shepherdmy/Desktop/testExcel.xlsx";
        // 读取用户信息两个sheet
        EasyExcel.read(fileName, User.class, new UserExcelListener()).sheet(0).doRead();
        EasyExcel.read(fileName, User.class, new UserExcelListener()).sheet(1).doRead();
        // 读取银行账户信息
        EasyExcel.read(fileName, Account.class, new AccountExcelListener()).sheet(2).doRead();
    }

执行结果:

解析到一条数据:User(id=1, userNo=uno:she001, gender=2, name=王小二, birthday=Fri Apr 12 10:00:00 CST 2024, phone=123456789, email=123456789@126.com, isDelete=null, address=杭州市余杭区未来科技城)
解析到一条数据:User(id=2, userNo=uno:she002, gender=2, name=张三, birthday=Wed Apr 10 18:00:00 CST 2024, phone=987654321, email=123456789@qq.com, isDelete=null, address=杭州市拱墅区城西银泰)
解析到一条数据:User(id=3, userNo=uno:she003, gender=2, name=李四, birthday=Thu Apr 11 18:00:00 CST 2024, phone=345686789, email=23445654@163.com, isDelete=null, address=上海陆家嘴浦东)
sheet=用户信息 所有数据解析完成!
解析到一条数据:User(id=5, userNo=uno:she005, gender=2, name=小五, birthday=Fri Apr 12 10:00:00 CST 2024, phone=123456789, email=123456789@126.com, isDelete=null, address=成都太古里)
解析到一条数据:User(id=6, userNo=uno:she006, gender=2, name=小六, birthday=Wed Apr 10 18:00:00 CST 2024, phone=987654321, email=123456789@qq.com, isDelete=null, address=上海南京路)
解析到一条数据:User(id=7, userNo=uno:she007, gender=2, name=小七, birthday=Thu Apr 11 18:00:00 CST 2024, phone=345686789, email=23445654@163.com, isDelete=null, address=杭州湖滨路)
sheet=用户信息2 所有数据解析完成!
表头数据:{0=姓名, 1=身份证号, 2=银行卡号, 3=余额, 4=状态, 5=最近使用时间}
解析到一条数据:Account(name=张三, idCard=3322114566, cardNo=62023445556, amount=10000.88, status=0, lastUsedTime=Sun Dec 31 00:00:00 CST 2023)
解析到一条数据:Account(name=李四, idCard=53134557, cardNo=623454576878, amount=6666.66, status=1, lastUsedTime=Sun Jun 11 00:00:00 CST 2023)
sheet=银行信息 所有数据解析完成!

3.EasyExcel数据导出

使用EasyExcel数据导出相对来说很简单,直接上代码,先来看看用户信息类User

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class User {
    @ExcelProperty(index = 0)
    private Long id;
    @ExcelProperty(index = 1, converter = UserNoConverter.class)
    private String userNo;
    @ExcelProperty(value = "性别", converter = GenderConverter.class)
    private Integer gender;
    @ExcelProperty(value = "姓名")
    private String name;
    @ExcelProperty(index = 4)
    private Date birthday;
    @ExcelProperty(index = 5)
    private String phone;
    @ExcelProperty(index = 6)
    private String email;
    @ExcelIgnore
    private Integer isDelete;
    @ExcelProperty(index = 7)
    private String address;
}

我们前面说过使用@ExcelProperty时,不建议同时使用index和value去映射属性,我这里这么写只是让你看看导出效果来突出使用value@ExcelProperty(value = "姓名")的好处,话不多说直接看测试用例,我造了10条用户信息数据导出:

    @Test
    public void testExcelWrite() {
        List<User> userList = new ArrayList<>();
        int i = 0;
        while (i < 10) {
            User user = User.builder().id((long)i).userNo("no-" + i).birthday(new Date()).gender(i%3)
                    .phone("123456789"+i).email("she12dfe@163.com").name("芽儿哟"+i).address("杭州"+i).build();
            userList.add(user);
            i++;
        }
        String fileName = "export.xlsx";
        EasyExcel.write(fileName, User.class).sheet("员工信息").doWrite(userList);

    }

导出文件如下所示:

图片

可以看到表头默认为属性名,使用@ExcelProperty(value = "姓名")就使用value更符合我们日常需求习惯。

假如导出大批量数据,我们不能一次性查出上百万条数据放入内存一次性导出,很有可能导致OOM,只能分页查询分批导出,实现如下:还是以上面的10天用户信息数据模拟,每3条处理一次导出

   @Test
    public void testExcelWrite() {
        List<User> userList = new ArrayList<>();
        int i = 0;
        while (i < 10) {
            User user = User.builder().id((long)i).userNo("no-" + i).birthday(new Date()).gender(i%3)
                    .phone("123456789"+i).email("she12dfe@163.com").name("芽儿哟"+i).address("杭州"+i).build();
            userList.add(user);
            i++;
        }
        String fileName = "export.xlsx";

        // 导出大批量数据,我们不能一次查询所有数据到内存中,只能分页查询导出,这里UserList假设需要分页导出,每页查询3条
        int size = userList.size();
        int page = size/ 3 + (size % 3 == 0 ? 0 : 1);
//        // 创建excelWriter
//        ExcelWriter excelWriter = EasyExcel.write(fileName, User.class).build();
//        // 创建writeSheet
//        WriteSheet writeSheet = EasyExcel.writerSheet(0,"分页员工信息").build();
//        for (int k = 0; k < page; k++) {
//            int start = k * 3;
//            int end = (k + 1) * 3 >= size ? size : (k + 1) * 3;
//            // 这里其实应该是分页查询数据,下面只是简单模拟下
//            List<User> users = userList.subList(start, end);
//            excelWriter.write(users, writeSheet);
//        }
//        // 关闭io才会写入数据,必须执行,所以最好用try-with-source安全,如下
//        excelWriter.finish();

        // 官方安全写法
        try (ExcelWriter excelWriter = EasyExcel.write(fileName, User.class).build()) {
            // 这里注意 如果同一个sheet只要创建一次
            WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
            // 去调用写入,实际使用时根据数据库分页的总的页数来
            for (int k = 0; k < page; k++) {
                // 分页去数据库查询数据 这里可以去数据库查询每一页的数据
                int start = k * 3;
                int end = (k + 1) * 3 >= size ? size : (k + 1) * 3;
                List<User> users = userList.subList(start, end);
                excelWriter.write(users, writeSheet);
            }
        }
    }

动态表头和动态数据

上面的示例都是映射Java类的,其实我可以直接导出excel,表头数据无外乎就是第一行,我们可以灵活设置即可:

  @Test
    public void testExport() {
        List<String> heads = ListUtils.newArrayList("员工编号", "姓名", "性别", "手机号", "金额");
        // 表头
        List<List<String>> dataList = new ArrayList<>();
        dataList.add(heads);
        int i = 0;
        while (i < 10) {
            i++;
            dataList.add(ListUtils.newArrayList(String.valueOf(i), "王"+i, i%2 == 0 ? "男" : "女", "1234456", "666.88"));
        }

        String fileName = "export.xlsx";
        EasyExcel.write(fileName).sheet("员工").doWrite(dataList);

    }

更多导出实现比如说设置单元格样式颜色啥的,可查看官方文档:https://easyexcel.opensource.alibaba.com/docs/current/quickstart/write

4.EasyExcel与poi对比

EasyExcel 和 Apache POI 是两个常用的 Java 库,用于处理 Excel 文件。它们有着一些相似之处,同时也有一些不同之处。以下是它们之间的对比:

易用性

  • EasyExcel:EasyExcel 提供了简单易用的 API,可以方便地进行 Excel 文件的读写操作。它使用了注解来简化开发者的操作,支持直接将 Java 对象写入 Excel 文件,也支持将 Excel 文件转换为 Java 对象。

  • Apache POI:Apache POI 是一个功能强大但相对复杂的库,需要较多的代码来完成 Excel 文件的读写操作。使用 POI 进行 Excel 操作通常需要处理大量的低级 API 调用和数据转换。

性能

  • EasyExcel:EasyExcel 在性能上表现优异,通过内存映射等技术来优化文件的读写操作,可以处理大型 Excel 文件而不会出现内存溢出等问题。

  • Apache POI:Apache POI 在处理大型 Excel 文件时可能会出现性能问题,特别是在写入大量数据时,可能会占用大量的内存和 CPU 资源。

功能丰富程度

  • EasyExcel:EasyExcel 提供了丰富的功能,支持多种样式、合并单元格、图片插入等功能,同时还提供了注解和模板的方式来简化开发者的操作。

  • Apache POI:Apache POI 是一个功能强大的库,提供了丰富的 API 来操作 Excel 文件,支持多种格式的 Excel 文件读写,并且可以进行复杂的操作,如图表、公式、宏等。

社区和文档支持

  • EasyExcel:EasyExcel 是阿里巴巴开源的项目,拥有活跃的社区和丰富的文档支持。开发者可以在社区中获取到丰富的使用经验和问题解决方案。

  • Apache POI:Apache POI 是 Apache 软件基金会的项目,拥有庞大的社区和完善的文档支持。开发者可以在官方网站上找到详尽的文档和示例代码。

总的来说,EasyExcel 相对于 Apache POI 更易于使用且性能更好,特别适合处理大型 Excel 文件和简单的数据导出导入需求。而 Apache POI 则更加灵活,支持更多复杂的 Excel 操作,适用于对功能要求较高的场景。选择使用哪个库取决于具体的需求和开发者的偏好

5.总结

EasyExcel 是一个功能强大、易于使用的 Excel 操作工具,它大大简化了 Excel 数据的读取和写入操作,提高了开发效率。通过本文的介绍,相信读者对 EasyExcel 库有了更深入的了解,希望能够在实际开发中更多地利用 EasyExcel 提升工作效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值