本文首发于我的个人网站:
http://riun.xyz
前言
程序中经常使用代码读取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。
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
Csv:1719条数据,499ms
依赖
<!--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
这个工具类我还会持续更新下去,欢迎给我提各种意见或建议(●’◡’●)