使用EasyExcel进行文件的读取与写出(根据目录看更清晰)

EasyExcel简介

Java领域解析、生成Excel比较有名的框架有Apache poi、jxl等。但他们都存在一个严重的问题就是非常的耗内存。如果你的系统并发量不大的话可能还行,但是一旦并发上来后一定会OOM或者JVM频繁的full gc。

easyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。easyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行行读取数据,逐个解析。

具体使用

读取文件

读取文件有两种方式:

1、使用readBySax方法进行读取,该方法适用于读取大量数据。
 EasyExcelFactory.readBySax(InputStream in, Sheet sheet, AnalysisEventListener listener)
2、使用read方法读取,该方法适用于读取少量数据。
 EasyExcelFactory.read(InputStream in, Sheet sheet)

下面就以上两种方式分别进行具体的使用

一、使用readBySax方法进行读取
1、从上述说明可以看出,该方法需要传入一个自定义监听器对象,因此我们自定义一个监听器,需要继承AnalysisEventListener并指明泛型(该泛型可以为一个自定义的类型,如User类,也可以是其他的类型,后面后具体讲述),重写invoke和doAfterAllAnalysed方法。
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;

import java.util.ArrayList;
import java.util.List;

/**
* @author : xukun
* @date : 2020/9/2
*/
public class AttrDataListener extends AnalysisEventListener<List<Object>> {

   //用于接收解析的所有数据
   private List<List<Object>> data = new ArrayList<>();

   //提供一个对外访问的方法
   public List<List<Object>> getData() {
       return data;
   }

   //记录解析的数据总数
   int count = 0;

   // easyexcel解析方式为一行一行解析,而每解析一行都会调用invoke方法
   // 该方法的第个参数位解析这一行的结果
   @Override
   public void invoke(List<Object> objects, AnalysisContext analysisContext) {
       //将这一行的解析结果添加到总数据集中
       data.add(objects);
       count++;
   }

   // 所有都解析完毕后要执行的操作
   @Override
   public void doAfterAllAnalysed(AnalysisContext analysisContext) {
       System.out.println("解析完毕,共" + (count - 1) + "条数据");
   }
}
2、准备好待解析的excel文件

在这里插入图片描述

3、进行解析
package com.shenlan.plains.excel.listener;

import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.metadata.Table;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @author : xukun
 * @date : 2020/9/2
 */
public class ExcelTest {
    public static void main(String[] args) {
        System.out.println("===读文件===");
        //待解析的文件路径
        String filePath1 = "C:\\Users\\SLDT\\Desktop\\utf-8''区域.xlsx";
        //第一个sheet,从第0行开始读取数据
        Sheet sheet1 = new Sheet(1, 0);
        //创建自定义的监听对象,后面要用这个对象去获取解析的数据
        AttrDataListener attrDataListener = new AttrDataListener();
        try {
            //传参,进行解析;会自动调用自定义监听器中的invoke方法
            EasyExcelFactory.readBySax(new FileInputStream(new File(filePath1)),sheet1,attrDataListener);
            //得到解析的数据
            List<List<Object>> data = attrDataListener.getData();
            //打印
            //打印
            for (List<Object> d : data){
                System.out.println(d);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
}
4、结果

在这里插入图片描述

附:泛型为指定类型:

被读取的文件:

在这里插入图片描述

1、该方式与类的属性一一对应,因此,我们首先创建一个User类,并且该类还要继承自BaseRowModel类同时使用@ExcelProperty注解指明表头名称和位置(若不指定,读取到的数据为空)。
package com.shenlan.plains.excel.listener;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.metadata.BaseRowModel;

/**
* @author : xukun
* @date : 2020/9/3
*/
public class User extends BaseRowModel {
   //value的值表示该列的表头名称为“序号”  index表示该列的位置,要与被读取的文件的表头一一对应
   @ExcelProperty(value = "序号",index = 0)
   private Integer id;
   @ExcelProperty(value = "学号",index = 1)
   private String sno;
   @ExcelProperty(value = "姓名",index = 2)
   private String sname;
   @ExcelProperty(value = "年龄",index = 3)
   private Integer age;
   //省略Getter、Setter和toString方法
}
2、使用监听器
package com.shenlan.plains.excel.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import org.apache.poi.ss.formula.functions.Count;

import java.util.ArrayList;
import java.util.List;

/**
* @author : xukun
* @date : 2020/9/3
*/
public class UserListener extends AnalysisEventListener<User> {

   private List<User> users = new ArrayList<>();

   public List<User> getUsers() {
       return users;
   }

   private int count = 0;

   @Override
   public void invoke(User user, AnalysisContext context) {
       users.add(user);
       count++;
   }

   @Override
   public void doAfterAllAnalysed(AnalysisContext context) {
       System.out.println("解析完毕,共解析"+count+"条数据");
   }
}
3、读取
package com.shenlan.plains.excel.listener;

import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.metadata.Table;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
* @author : xukun
* @date : 2020/9/2
*/
public class ExcelTest {
   public static void main(String[] args) {
       System.out.println("===读文件===");
       //待解析的文件路径
       String filePath3 = "C:\\Users\\SLDT\\Desktop\\学生.xlsx";
       //第一个sheet,从第1行开始读取数据(第0行,也就是表头,与User不匹配,所以从第1行开始读取)
       Sheet sheet3 = new Sheet(1, 1,User.class);
       //创建自定义的监听对象,后面要用这个对象去获取解析的数据
       UserListener userListener = new UserListener();
       try {
           //传参,进行解析;会自动调用自定义监听器中的invoke方法
           EasyExcelFactory.readBySax(new FileInputStream(new File(filePath3)),sheet3,userListener);
           //得到解析的数据
           List<User> users = userListener.getUsers();
           //打印
           for (User user : users){
               System.out.println(user);
           }
       } catch (FileNotFoundException e) {
           e.printStackTrace();
       }
   }
}

注意:在new Sheet时使用的时另一个要传入类对象的构造方法

Sheet sheet3 = new Sheet(1, 1,User.class);
4、结果

在这里插入图片描述

二、使用read方法进行读取
1、由于不需要使用监听器,所以我们直接准备待解析的文件即可。(其实源码里面自己创建了一个监听器对象)

在这里插入图片描述
待解析文件:
在这里插入图片描述

2、解析文件
package com.shenlan.plains.excel.listener;

import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.metadata.Table;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @author : xukun
 * @date : 2020/9/2
 */
public class ExcelTest {
    public static void main(String[] args) {
        System.out.println("===读文件===");
        //待解析的文件路径
        String filePath1 = "C:\\Users\\SLDT\\Desktop\\utf-8''区域.xlsx";
        //第一个sheet,从第0行开始读取数据
        Sheet sheet1 = new Sheet(1, 0);
        try {
            得到解析的数据
            List<Object> data = EasyExcelFactory.read(new FileInputStream(new File(filePath1)),sheet1);
            //打印
            for (Object d : data){
                System.out.println(d);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
}
3、结果

在这里插入图片描述

写出文件

写文件有两种方式

第一种:生成动态表头的excel文件
第二种:生成指定表头的excel文件
下面就以上两种方式进行说明:

一、生成动态表头
1、代码如下:
package com.shenlan.plains.excel.listener;

import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.metadata.Table;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @author : xukun
 * @date : 2020/9/2
 */
public class ExcelTest {
    public static void main(String[] args) {
        System.out.println("===写文件===");
        String filePath2 = "C:\\Users\\SLDT\\Desktop\\test.xlsx";
        //第一个sheet,从第0行开始写数据
        Sheet sheet2 = new Sheet(1,0);
        sheet2.setSheetName("test");

        //自定义表格
        Table table = new Table(1);
        //所有表头的集合
        List<List<String>> head = new ArrayList<>();
        //后续这些表头可根据自己的需求动态生成,比如,可通过循环生成等,可能有一些业务,它的表头需要从数据库中查询得到
        ArrayList<String> head0 = new ArrayList<>();
        head0.add("姓名");//第一列表头
        ArrayList<String> head1 = new ArrayList<>();
        head1.add("学号");//第二列表头
        ArrayList<String> head2 = new ArrayList<>();
        head2.add("性别");//第三列表头

        head.add(head0);
        head.add(head1);
        head.add(head2);
        //将表头添加到表中
        table.setHead(head);

        //写
        try {
            //传参
            ExcelWriter writer = EasyExcelFactory.getWriter(new FileOutputStream(new File(filePath2)));
            writer.write0(getExcelData(), sheet2, table);
            writer.finish();//记住,一定要关闭资源,否则写出的文件为空
            System.out.println("文件写出完毕");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
    /**
     * 写入到文件中的数据,为空时相当于一个模板
     * 在具体的业务中,这些数据从数据库获取
     */
    private static List<List<String>> getExcelData() {
        return null;
    }
}

2、结果:

在这里插入图片描述

3、写出的文件:

在这里插入图片描述

二、生成指定表头
1、该方式一般生成的表头与类的属性一一对应,因此,我们首先创建一个User类,并且该类还要继承自BaseRowModel类(后续会说明原因),同时使用@ExcelProperty注解指明表头名称和位置。
package com.shenlan.plains.excel.listener;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.metadata.BaseRowModel;

/**
 * @author : xukun
 * @date : 2020/9/3
 */
public class User extends BaseRowModel {
    //value的值表示该列的表头名称为“序号”  index表示该列的位置
    @ExcelProperty(value = "序号",index = 0)
    private Integer id;
    @ExcelProperty(value = "学号",index = 1)
    private String sno;
    @ExcelProperty(value = "姓名",index = 2)
    private String sname;
    @ExcelProperty(value = "年龄",index = 3)
    private Integer age;
	//省略Getter、Setter和toString方法
}
2、写文件
package com.shenlan.plains.excel.listener;

import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.metadata.Table;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @author : xukun
 * @date : 2020/9/2
 */
public class ExcelTest {
    public static void main(String[] args) {
        //写出文件
        String filePath4 = "C:\\Users\\SLDT\\Desktop\\学生.xlsx";
        try {
            //传参
            ExcelWriter writer = EasyExcelFactory.getWriter(new FileOutputStream(new File(filePath4)));
            Sheet sheet4 = new Sheet(1, 0, User.class);
            //自定义表格
            Table table4 = new Table(1);
            writer.write0(getExcelData(), sheet4, table4);
            writer.finish();
            System.out.println("写文件完毕");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 写入到文件中的数据,为空时相当于一个模板
     * 在具体的业务中,这些数据从数据库获取
     */
    private static List<List<String>> getExcelData() {
        return null;
    }
}

可以看出,在该方式中,我们使用的时Sheet的另一个重载的构造方法,在该方法中会传入一个继承自BaseRowModel的类的类对象,我们也可以从源码传参看到。
在这里插入图片描述
所以,前面在定义类的时候就需要让该类继承BaseRowModel类。
同时,该方式中的Table对象我们只是创建出来,并没有设置任何关于表头的属性。这是因为关于表头的信息我们都在自定义类中定义好了。

3、结果

控制台结果:
在这里插入图片描述
生成的表格:
在这里插入图片描述
至此,使用EasyExcel进行文件的读取与写出就到此结束。

  • 6
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
EasyExcel是一个用于读写Excel文件Java库,它提供了简单易用的API来读取、写入和操作Excel文件。下面是一个简单的示例,演示如何使用EasyExcel读取Excel文件: 1. 首先,你需要在你的项目中添加EasyExcel的依赖。如果你使用Maven,你可以在你的pom.xml文件中添加以下依赖: ``` <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.3.0</version> </dependency> ``` 2. 接下来,你需要创建一个Java类来表示你的Excel数据。例如,如果你要读取一个包含学生信息的Excel文件,你可以创建一个`Student`类: ``` public class Student { private String name; private int age; private String gender; // getter and setter methods } ``` 3. 然后,你可以使用EasyExcel的API来读取Excel文件。以下代码演示了如何读取一个包含学生信息的Excel文件: ``` public void readExcel() { String fileName = "path/to/file.xlsx"; List<Student> students = new ArrayList<>(); EasyExcel.read(fileName, Student.class, new AnalysisEventListener<Student>() { @Override public void invoke(Student student, AnalysisContext context) { students.add(student); } @Override public void doAfterAllAnalysed(AnalysisContext context) { // do something after all rows are read } }).sheet().doRead(); // do something with the students list } ``` 在上面的代码中,`EasyExcel.read()`方法接受三个参数:Excel文件的路径、Java类(表示Excel数据的类型)、和一个`AnalysisEventListener`实例。`AnalysisEventListener`是EasyExcel提供的一个接口,用于处理Excel数据。在`invoke()`方法中,你可以将读取到的Excel数据添加到一个List中,而在`doAfterAllAnalysed()`方法中,你可以在所有行都读取完毕后进行一些操作。最后,使用`sheet().doRead()`方法来开始读取Excel文件。 4. 最后,你可以根据你的需要处理读取到的Excel数据。例如,你可以将学生信息存储到数据库中,或者将它们写入到另一个Excel文件中。 以上就是使用EasyExcel读取Excel文件的简单示例。EasyExcel还提供了很多其他的功能,例如写入Excel文件、处理大型Excel文件等。你可以在EasyExcel的官方文档中了解多信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值