抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

读文件

前言

在网上找了许多文档,大多数都太老了又或者都是互相复制。就连官方的文档也是写的对新手不够友好,因此将学习过程记录下来。

使用环境部署

这个步骤网上绝大部分都没有说,建议先和我使用相同的版本,熟悉后在更换最新版本。
在这里我使用maven管理器来管理包。

// pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>easyExcelDemo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>
    <dependencies>
<!--关键加上这两个包开始-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
              <groupId>org.slf4j</groupId>
              <artifactId>slf4j-simple</artifactId>
              <version>1.7.25</version>
              <scope>compile</scope>
        </dependency>
<!--关键加上这两个包结束-->
    </dependencies>
</project>

导入后的包
博客EasyExcel导入库

一个简单的读取Excel文件

新建ExcelReaderBuilder读取流

  ExcelReaderBuilder readerBuilder = EasyExcel.read();

给文件流传入Excel路径或者File对象

readerBuilder.file("C:\\***\\2021学生信息.xlsx");
// 或
readerBuilder.file(new File("C:\\***.xlsx"));

指定sheet名字,或者下标

readerBuilder.sheet("Sheet1");

为了节省内存,在这里应该加上自动关闭文件流

readerBuilder.autoCloseStream(true);

因为Excel有多个版本,需要指定版本

readerBuilder.excelType(ExcelTypeEnum.XLSX);

到了这里,已经将Excel配置到了。接下来我们来监听读取文件流。
registerReadListener会一行一行的回调到invoke函数,只要调用返回的参数即可。读取完全部文件后会调用doAfterAllAnalysed

readerBuilder.registerReadListener(new AnalysisEventListener() {
    @Override
    public void invoke(Object o, AnalysisContext analysisContext) {
        // 读完一行的回调函数操作
        System.out.println(o);
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        // 读完所有的数据后的回调函数操作
        System.out.println("读完所有的数据后的回调函数操作");
    }
});

到了这里,其实还不能读取到数据,因为该工作流并没有启动,我们需要构建读取器。

ExcelReader reader = readerBuilder.build();
// 构建读取器

再启动,读取全部数据

reader.readAll();
// 读取全部数据

关闭读取器

reader.finish();
// 关闭读取器

全部代码

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.read.builder.ExcelReaderBuilder;
import com.alibaba.excel.support.ExcelTypeEnum;

import java.io.File;

public class Test {
    public static void main(String[] args) {
        ExcelReaderBuilder readerBuilder = EasyExcel.read();
        // 创建一个 ExcelReader 对象
        readerBuilder.file("C:\\Users\\zy\\Desktop\\Porject\\School-Assignment\\Java\\GetStudentGrades\\src\\resources\\2021学生信息.xlsx");
        // 获取文件对象
        readerBuilder.sheet("Sheet1");
        // 指定sheet名称
        readerBuilder.autoCloseStream(true);
        // 自动关闭流
        readerBuilder.excelType(ExcelTypeEnum.XLSX);
        // 设置excel类型
        readerBuilder.registerReadListener(new AnalysisEventListener() {
            @Override
            public void invoke(Object o, AnalysisContext analysisContext) {
                // 读完一行的回调函数操作
                System.out.println(o);
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                // 读完所有的数据后的回调函数操作
                System.out.println("读完所有的数据后的回调函数操作");
            }
        });
        ExcelReader reader = readerBuilder.build();
        // 构建读取器
        reader.readAll();
        // 读取全部数据
        reader.finish();
        // 关闭读取器fanxing
    }
}

优化代码

由于invoke回调函数默认传入的Object对象,在这里建议使用泛型来限定类型,重写readerBuilder.registerReadListener方法

readerBuilder.registerReadListener(new AnalysisEventListener<Map<Integer, String>>() {
    // 将接口的泛型指定为实体类型
    @Override
    public void invoke(Map<Integer, String> integerStringMap, AnalysisContext analysisContext) {
        // 指定传入的实体类型为Map<Integer, String>
        Set<Integer> keySet = integerStringMap.keySet();
        // 获取map的key
        Iterator<Integer> iterator = keySet.iterator();
        // 获取map的key的迭代器
        while (iterator.hasNext()) {
            Integer next = iterator.next();
            System.out.println(next + ":" + integerStringMap.get(next));
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        ...
    }
});

简化代码

以上的代码是该类的正常写法,但是显得过于繁重,应此可以向下面那样简化代码。

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;

import java.util.*;

public class Test2 {
    public static void main(String[] args) {
        List<Map<Integer, String>> list = new LinkedList<>();
        // 定义一个集合来接收解析出来的数据
        EasyExcel.read("C:\\Users\\zy\\Desktop\\Porject\\School-Assignment\\Java\\GetStudentGrades\\src\\resources\\2021学生信息.xlsx")
                .sheet()
                // 指定读取的sheet,不写则读全部
                .registerReadListener(new AnalysisEventListener<Map<Integer, String>>() {
                    @Override
                    public void invoke(Map<Integer, String> integerStringMap, AnalysisContext analysisContext) {
                        list.add(integerStringMap);
                        // 指定传入的实体类型为Map<Integer, String>
                    }

                    @Override
                    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                        System.out.println("读完所有的数据了");
                    }
                }).doRead();
        for (Map<Integer, String> map : list) {
            Set<Integer> keySet = map.keySet();
            Iterator<Integer> iterator = keySet.iterator();
            while (iterator.hasNext()) {
                Integer next = iterator.next();
                System.out.println(next + ":" + map.get(next));
            }
        }
    }
}

使用ExcelProperty注解

我们可以使用该注解来限制对象的属性对应的列

import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;

@Data
@Getter
@Setter
public class ExcelData {
    @ExcelProperty(value = "姓名")
    // 此注解可以指定读取的列
    private String name;
    @ExcelProperty(value = "班级")
    private String className;
}

自定义一个对象来存储Excel

现在,已经掌握了大部分的方法,话不多说直接上代码。

// ExcelData
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;

@Data
@Getter
@Setter
public class ExcelData {
    @ExcelProperty(value = "姓名")
    // 此注解可以指定读取的列
    private String name;
    @ExcelProperty(value = "班级")
    private String className;
}
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;

import java.util.*;

public class Test2 {
    public static void main(String[] args) {
        List<ExcelData> list = new LinkedList<>();
        // 定义一个集合来接收解析出来的数据
        EasyExcel.read("C:\\Users\\zy\\Desktop\\Porject\\School-Assignment\\Java\\GetStudentGrades\\src\\resources\\2021学生信息.xlsx")
                .head(ExcelData.class)
                // 根据指定的实体类去解析Excel转为LinkedHashMap
                .sheet()
                // 指定读取的sheet,不写则读全部
                .registerReadListener(new AnalysisEventListener<ExcelData>() {
                    @Override
                    public void invoke(ExcelData excelData, AnalysisContext analysisContext) {
                        list.add(excelData);
                    }

                    @Override
                    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                        System.out.println("读完所有的数据了");
                    }
                }).doRead();
        for (ExcelData excelData : list) {
            System.out.println(excelData);
        }
    }
}

写文件

使用EasyExcel.write()来写入文件。

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.support.ExcelTypeEnum;

import java.util.*;

public class Test2 {
    public static void main(String[] args) {
        List<ExcelData> dataList = parseData();
        // 读取的数据,拿来写
        EasyExcel.write("E:\\测试写入副本.xlsx")
                .head(ExcelData.class)
                .excelType(ExcelTypeEnum.XLSX)
                .sheet("测试表")
                .doWrite(dataList);
    }

    /* 将读取的数据再次利用来写文件 */
    public static List<ExcelData> parseData(){
        List<ExcelData> list = new LinkedList<>();
        // 定义一个集合来接收解析出来的数据
        EasyExcel.read("C:\\Users\\zy\\Desktop\\Porject\\School-Assignment\\Java\\GetStudentGrades\\src\\resources\\2021学生信息.xlsx")
                .head(ExcelData.class)
                // 根据指定的实体类去解析Excel转为LinkedHashMap
                .sheet()
                // 指定读取的sheet,不写则读全部
                .registerReadListener(new AnalysisEventListener<ExcelData>() {
                    @Override
                    public void invoke(ExcelData excelData, AnalysisContext analysisContext) {
                        list.add(excelData);
                    }

                    @Override
                    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
                        System.out.println("读完所有的数据了");
                    }
                }).doRead();
        return list;
    }
}

评论