前言

程序中经常使用代码读取Excel或Csv文件,每次都要写繁琐的读取代码,于是我就写了一个工具类去读取文件,并将结果储存为常用的格式。方便我们快速的拿到结果进行入库或其他处理。不再将精力浪费在处理文件上。

下面我将全面介绍此工具类。

预备知识

csv文件,一种文本文件格式,以行为单位储存数据。每行中的数据以逗号分隔,可以以excel方式打开。

poi,一种java读取excel文件的工具。可以对行,或特定的单元格进行读取。

使用

案例:读取Excel文件

1、准备一个Excel文件,你可以点这儿下载一个( https://github.com/hanhanhanxu/HPoiUtil/blob/master/pleasedownloadme/testexcel.xlsx )【鼠标放在链接上,选择‘链接另存为’】,或者准备你自己的。我的文件中的数据是这样的:

部门名称

班级名称

学号

姓名

收费年度

总账欠费金额

欠费金额

1

16软件工程(JAVA技术应用方向)

45asdf4w23

路飞

2019年度

13,800.00

13,800.00

2

16软件工程(JAVA技术应用方向)

34534sdf34

乌索普

2019年度

5,800.00

5,800.00

3

软件设计

346e5tertw

索隆

2019年度

13,800.00

13,800.00

4

软件设计

3456eyerge

山治

2019年度

13,800.00

13,800.00

5

软件设计

345e4twset

娜美

2019年度

13,800.00

13,800.00

6

软件设计

345634etr2

罗宾

2019年度

13,800.00

13,800.00

2、准备pojo对象。此对象的含义是,你最终将读取到的Excel文件中的数据转化为什么对象。比如我excel文件中的数据其实是学生 Student 对象,那么就新建一个 Student.java。

package riun.xyz.Demo4;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

/**
 * @author: HanXu
 * on 2019/06/18
 * Class description:
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
    private Integer id;
    private Integer depId;
    private String className;
    private String sno;
    private String name;
    private String year;
    private Float allAmountArrears;
    private Float amountArrears;
    private Date createTime;
}

Excel文件中每列都有它的含义,对应着pojo类的属性。下面是属性对照关系。需要注意的是,允许存在pojo类中有的属性,而Excel没有那一列数据。例如本例中的id,createTime。

poi导出csv文件 java poi读取csv文件_java

3、获取HPoiUtils.java 的源码,你可以点这儿下载( https://github.com/hanhanhanxu/HPoiUtil/blob/master/pleasedownloadme/HPoiUtils.java )【鼠标放在链接上,选择‘链接另存为’】。

4、编写测试案例。

想要读取Excel文件中的数据,你需要在代码里准备一个文件file;一个集合list,此集合中存放的是Excel文件中每列代表含义,即这列映射到pojo中的属性名字。必选的只有这两个参数,让我们试试:

package riun.xyz.nice.Demo1.all;

import org.apache.commons.beanutils.BeanUtils;
import riun.xyz.Demo4.HPoiUtils;
import riun.xyz.Demo4.Student;

import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;

/**
 * @author: HanXu
 * on 2020/6/18
 * Class description: 读取excel文件的测试
 */
public class Test {

    //准备文件file
    static final File file = new File("D:\\05HxUtils\\1\\testexcel.xlsx");
    //准备属性集合list
    private static List<String> genListField() {
        List<String> listField = new ArrayList(12);//建议使用ArrayList,get(i)操作更快
        listField.add("depId");
        listField.add("className");
        listField.add("sno");
        listField.add("name");
        listField.add("year");
        listField.add("allAmountArrears");
        listField.add("amountArrears");
        return listField;
    }


    public static void main(String[] args) {
        test2();
    }

    public static void test2() {
        List<String> listField = genListField();
        //执行
        List result = HPoiUtils.exe(file, listField);
        for (Object o : result) {
            //类格式输出
            Student student = new Student();
            try {
                BeanUtils.copyProperties(student, o);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
            System.out.println(student);
            
            //json格式输出
            /*System.out.println( nice GsonBuilder().setPrettyPrinting().create().toJson(o));
            System.out.println();*/
        }
        System.out.println("共" + result.size() + "条记录");
    }
}

输出内容为:

Student(id=null, depId=1, className=16软件工程(JAVA技术应用方向), sno=45asdf4w23, name=高新杰, year=2019年度, allAmountArrears=13800.0, amountArrears=13800.0, createTime=null)
Student(id=null, depId=2, className=16软件工程(JAVA技术应用方向), sno=34534sdf34, name=刘德华, year=2019年度, allAmountArrears=5800.0, amountArrears=5800.0, createTime=null)
Student(id=null, depId=3, className=软件设计, sno=346e5tertw, name=许文瑞, year=2019年度, allAmountArrears=13800.0, amountArrears=13800.0, createTime=null)
Student(id=null, depId=4, className=软件设计, sno=3456eyerge, name=张奕东, year=2019年度, allAmountArrears=13800.0, amountArrears=13800.0, createTime=null)
Student(id=null, depId=5, className=软件设计, sno=345e4twset, name=蒋海靖, year=2019年度, allAmountArrears=13800.0, amountArrears=13800.0, createTime=null)
Student(id=null, depId=6, className=软件设计, sno=345634etr2, name=徐凯, year=2019年度, allAmountArrears=13800.0, amountArrears=13800.0, createTime=null)
共6条记录

已经成功读取 Excel文件并将结果转化为Student对象,接下来你就可以开心的做其他处理啦。

参数含义

上述代码只使用一行HPoiUtils.exe就能读取到文件,拿到结果对象集合了。下面将介绍此方法的几个参数:

  • file:一个Excel文件。必选
  • sheetIndex或sheetName:sheetIndex代表sheet索引值,即第几个sheet,从0开始;sheetName代表sheet名字。可选,默认为0,即读取第一个sheet的内容
  • list:属性集合,集合中的元素代表Excel中对应列的意义,一一对应。必选
  • class:表示想要转化成的对象,即将Excel表中的行记录转化为什么对象。可选,不传入时会根据传入list的内容动态生成一个类。大多数时候,建议手动传入
  • hasHeader:Excel中是否有有表头,true,是,则读取时不会读取第一行数据;false,否,当你的Excel文件中没有表头,第一行就是数据时,传入false。可选,默认为true

共有5个参数,其中两个是必选的,其他是非必选的。就是说还能使用其他方式读取,例如:

List result = HPoiUtils.exe(file, listField, false); # 读取时将认为Excel文件中没有表头,会把第一行也认为是数据并读取转化为对象。

List result = HPoiUtils.exe(file, 1, listField); # 读取Excel中的第1个sheet(为0时可不传,表示读取第一个;为1表示读取第二个sheet;此处也可传入sheet名字,不区分大小写)

List<Student> result = HPoiUtils.exe(file, listField, Student.class); # 读取到的数据直接就是Student,不用再转换。通常情况下,建议传入类。

你也可以选择5个参数全部手动传入。

案例:读取Csv文件

1、准备一个Csv文件,你可以点这儿下载一个【文件testcsv.csv】,或者准备你自己的。我的文件中的数据是这样的:

id,name,pass,age,sary
1,qweqw,asdfa,12.32
2,45wes,dfgdf,435.309
3,asdt,asdf,345.23

2、准备pojo对象。此对象的含义是,你最终将读取到的Csv文件中的数据转化为什么对象。比如我csvl文件中的数据其实是员工 Emp 对象,那么就新建一个 Emp.java。

package riun.xyz.nice.Demo1.all;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author: Hanxu
 * @Date: 2020/6/18 22:21
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Emp {
    private Long id;
    private String name;
    private String pass;
    private Float sary;
    private String other;
}

3、获取HPoiUtils.java 的源码。

4、编写测试案例。

想要读取Csv文件中的数据,你需要在代码里准备一个文件file;一个集合list,此集合中存放的是Csv文件中每列代表含义,即这列映射到pojo中的属性名字。必选的只有这两个参数,但是我们通常都建议明确传入class对象,即Emp.class对象,让我们试试:

package riun.xyz.nice.Demo1.all;

import riun.xyz.Demo5.RepeaterDebtTermDto;

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

/**
 * @author: HanXu
 * on 2020/6/16
 * Class description: 读取Csv文件的测试
 */
public class Test {

    //准备文件file
    static final File file = new File("D:\\05HxUtils\\1\\testcsv.csv");
    //准备属性集合list
    private static List<String> genListField() {
        List<String> listField = new ArrayList(10);//建议使用ArrayList,get(i)操作更快
        listField.add("id");
        listField.add("name");
        listField.add("pass");
        listField.add("sary");
        return listField;
    }

    public static void main(String[] args) {
        test1();
    }

    public static void test1() {
        List<String> listField = genListField();
        //执行
        List<Emp> result = HPoiUtils.exeCsv(file, listField, Emp.class);
        for (Emp o : result) {
            System.out.println(o);
            //System.out.println( nice GsonBuilder().setPrettyPrinting().create().toJson(o));
        }
        System.out.println(result.size());
    }

}

输出内容为:

Emp(id=1, name=qweqw, pass=asdfa, sary=12.32, other=null)
Emp(id=2, name=45wes, pass=dfgdf, sary=435.309, other=null)
Emp(id=3, name=asdt, pass=asdf, sary=345.23, other=null)
3

已经得到对象集合数据了,接下来可以进行入库或者其他处理了。

参数含义

上述代码仍然是使用一行List<Emp> result = HPoiUtils.exeCsv(file, listField, Emp.class);即可读取到文件中的数据并转化为对象集合返回。其中参数和上面读取Excel文件时差不多,只少了一个sheet参数。

下面是参数解释:

  • file:csv文件。必选
  • listField:文件中每列代表的属性名字集合。必选
  • class:文件中每行对应的对象。可选,不传入时程序在运行期间会生成一个动态类。
  • hasHeader:是否有表头信息。可选,默认为true,即有表头信息。

性能测试

上面读取到的数据都太小了,我们换一个稍微大点的文件试试:

Excel:125条数据,712ms

poi导出csv文件 java poi读取csv文件_数据_02

Csv:1719条数据,499ms

poi导出csv文件 java poi读取csv文件_数据_03

依赖

<!--poi-->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.17</version>
</dependency>
<!--javassist.*-->
<dependency>
    <groupId>org.javassist</groupId>
    <artifactId>javassist</artifactId>
    <version>3.18.2-GA</version>
</dependency>
<!--工具类-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.5</version>
</dependency>
<!--pojo类的setter getter等方法-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.12.6</version>
</dependency>
<!--不传入类时,类拷贝-->
<dependency>
    <groupId>commons-beanutils</groupId>
    <artifactId>commons-beanutils</artifactId>
    <version>1.9.3</version>
</dependency>
<!--输出json样式-->
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.5</version>
</dependency>

源码解释

本工具处理过程大致分为如下几步:

1、参数检查

2、获取String结果

3、将String结果对象化

其中第2步,获取String结果时,根据不同文件,按照给定的sheet进行读取,读取时不会判断是否有表头,将全部数据读取,根据传入的list.size可以进行逻辑分组。

第3步,String对象化时使用了反射,如果传入有类,就按照类动态生成对象,并根据list中储存的属性名字动态执行setter方法,将读取到的String类型的数据设置进去。

如果没有传入类,就动态生成一个类,然后再执行上述。

关于

此工具是我之前HPoiUtils的前身,当时指向读取Excel文件,后来写着写着就加上了读取Csv文件,更多详细及历史版本参见github:https://github.com/hanhanhanxu/HPoiUtil

这个工具类我还会持续更新下去,欢迎给我提各种意见或建议(●’◡’●)