本文使用基于阿里的easyexcel编写的工具类对xls后缀的Excel文件(即03版)读取并写成xlsx后缀的Excel文件(即07版),中间转换过程使用String二维数组和对象列表两种形式.
easyexcel 项目git地址为: https://github.com/alibaba/easyexcel
官方使用指南见: https://github.com/alibaba/easyexcel/blob/master/quickstart.md
文章目录
一 工具类
/**
* @version V1.0
* @author: lin_shen
* @date: 2018/9/26
* @Description: TODO
*/
public class EasyExcelUtil {
/**
* StringList 解析监听器
*/
private static class StringExcelListener extends AnalysisEventListener {
/**
* 自定义用于暂时存储data
* 可以通过实例获取该值
*/
private List<List<String>> datas = new ArrayList<>();
/**
* 每解析一行都会回调invoke()方法
* @param object
* @param context
*/
@Override
public void invoke(Object object, AnalysisContext context) {
List<String> stringList= (List<String>) object;
//数据存储到list,供批量处理,或后续自己业务逻辑处理。
datas.add(stringList);
//根据自己业务做处理
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
//解析结束销毁不用的资源
//注意不要调用datas.clear(),否则getDatas为null
}
public List<List<String>> getDatas() {
return datas;
}
public void setDatas(List<List<String>> datas) {
this.datas = datas;
}
}
/**
* 使用 StringList 来读取Excel
* @param inputStream Excel的输入流
* @param excelTypeEnum Excel的格式(XLS或XLSX)
* @return 返回 StringList 的列表
*/
public static List<List<String>> readExcelWithStringList(InputStream inputStream,ExcelTypeEnum excelTypeEnum) {
StringExcelListener listener = new StringExcelListener();
ExcelReader excelReader = new ExcelReader(inputStream, excelTypeEnum, null, listener);
excelReader.read();
return listener.getDatas();
}
/**
* 使用 StringList 来写入Excel
* @param outputStream Excel的输出流
* @param data 要写入的以StringList为单位的数据
* @param table 配置Excel的表的属性
* @param excelTypeEnum Excel的格式(XLS或XLSX)
*/
public static void writeExcelWithStringList(OutputStream outputStream, List<List<String>> data, Table table,ExcelTypeEnum excelTypeEnum) {
//这里指定不需要表头,因为String通常表头已被包含在data里
ExcelWriter writer = new ExcelWriter(outputStream, excelTypeEnum,false);
//写第一个sheet, sheet1 数据全是List<String> 无模型映射关系,无表头
Sheet sheet1 = new Sheet(0, 0);
writer.write0(data, sheet1,table);
writer.finish();
}
/**
* 模型 解析监听器
*/
private static class ModelExcelListener extends AnalysisEventListener {
private List<Object> datas = new ArrayList<>();
@Override
public void invoke(Object object, AnalysisContext context) {
datas.add(object);
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
}
public List<Object> getDatas() {
return datas;
}
public void setDatas(List<Object> datas) {
this.datas = datas;
}
}
/**
* 使用 模型 来读取Excel
* @param inputStream Excel的输入流
* @param clazz 模型的类
* @param excelTypeEnum Excel的格式(XLS或XLSX)
* @return 返回 模型 的列表(为object列表,需强转)
*/
public static List<Object> readExcelWithModel(InputStream inputStream, Class<? extends BaseRowModel> clazz,ExcelTypeEnum excelTypeEnum) {
// 解析每行结果在listener中处理
ModelExcelListener listener = new ModelExcelListener();
ExcelReader excelReader = new ExcelReader(inputStream, excelTypeEnum, null, listener);
//默认只有一列表头
excelReader.read(new Sheet(1,1,clazz));
return listener.getDatas();
}
/**
* 使用 模型 来写入Excel
* @param outputStream Excel的输出流
* @param data 要写入的以 模型 为单位的数据
* @param table 配置Excel的表的属性
* @param clazz 模型的类
* @param excelTypeEnum Excel的格式(XLS或XLSX)
*/
public static void writeExcelWithModel(OutputStream outputStream, List<? extends BaseRowModel> data, Table table,Class<? extends BaseRowModel> clazz,ExcelTypeEnum excelTypeEnum) {
//这里指定需要表头,因为model通常包含表头信息
ExcelWriter writer = new ExcelWriter(outputStream, excelTypeEnum,true);
//写第一个sheet, sheet1 数据全是List<String> 无模型映射关系
Sheet sheet1 = new Sheet(1,0, clazz);
writer.write(data, sheet1,table);
writer.finish();
}
}
二 编写excel对应Java对象
现有excel格式如下:
故定义对应Java对象如下:
注意:@ExcelProperty注解的value值对应的是Excel表格的表头内容
@Data
public class ETUInfo extends BaseRowModel {
@ExcelProperty(value ={"TxHash"},index = 0)
private String txHash;
@ExcelProperty(value ={"Date"},index =1)
private String date;
@ExcelProperty(value ={"From"},index = 2)
private String from;
@ExcelProperty(value ={"To"},index = 3)
private String to;
@ExcelProperty(value ={"Quantity"},index = 4)
private String quantity;
}
三 使用两种方法测试
第一种使用了String列表对Excel属性进行解析,每一行对应一个List,这样灵活性高,注意表头也会被当成List。
第二种使用了Model对Excel属性进行解析,每一行对应一个 Model,也就是Java对象,这样可以直接将excel文件解析为对象列表,方便后续操作。
两种方法都是将xls格式读入再以xlsx格式写出。
注意还可以利用TableStyle设置Excel格式(主要是字体大小和颜色),默认是很丑的,而且目前最新版本EasyExcel还不能设置单元格内容居中和自动适应宽度
public class EasyExcelUtilTest {
@Test
public void testReadExcelWithStringList(){
try(
InputStream inputStream=new FileInputStream("C:\\Users\\Shinelon\\IdeaProjects\\webmagic\\webmagic\\src\\test\\java\\etherscan-page1-1000.xls");
OutputStream outputStream=new FileOutputStream("C:\\Users\\Shinelon\\IdeaProjects\\webmagic\\webmagic\\src\\test\\java\\etherscan-page1-1000String.xlsx")
) {
//读入文件,每一行对应一个List<String>
List<List<String>> stringLists = EasyExcelUtil.readExcelWithStringList(inputStream, ExcelTypeEnum.XLS);
//定义Excel正文背景颜色
TableStyle tableStyle=new TableStyle();
tableStyle.setTableContentBackGroundColor(IndexedColors.WHITE);
//定义Excel正文字体大小
Font font=new Font();
font.setFontHeightInPoints((short) 10);
tableStyle.setTableContentFont(font);
Table table=new Table(0);
table.setTableStyle(tableStyle);
EasyExcelUtil.writeExcelWithStringList(outputStream,stringLists,table,ExcelTypeEnum.XLSX);
} catch (IOException e) {
e.printStackTrace();
}
}
@Test
public void testReadExcelWithModel(){
try (
InputStream inputStream=new FileInputStream("C:\\Users\\Shinelon\\IdeaProjects\\webmagic\\webmagic\\src\\test\\java\\etherscan-page1-1000.xls");
OutputStream outputStream=new FileOutputStream("C:\\Users\\Shinelon\\IdeaProjects\\webmagic\\webmagic\\src\\test\\java\\etherscan-page1-1000model.xlsx")
) {
//读入文件,每一行对应一个 Model ,获取Model 列表
List<Object> objectList = EasyExcelUtil.readExcelWithModel(inputStream,ETUInfo.class,ExcelTypeEnum.XLS);
List<ETUInfo> etuInfoList=(List)objectList;
//定义Excel正文背景颜色
TableStyle tableStyle=new TableStyle();
tableStyle.setTableContentBackGroundColor(IndexedColors.WHITE);
//定义Excel正文字体大小
Font font=new Font();
font.setFontHeightInPoints((short) 10);
tableStyle.setTableContentFont(font);
Table table=new Table(0);
table.setTableStyle(tableStyle);
EasyExcelUtil.writeExcelWithModel(outputStream,etuInfoList,table,ETUInfo.class,ExcelTypeEnum.XLSX);
} catch (IOException e) {
e.printStackTrace();
}
}
}
四 查看输出结果
可以看到比较明显的区别是在表头部分,String并没有设置表头,对于EasyExcel来说第一行的数据和第二行没什么区别,需要的话得将第一行的数据去除,再单独设置表头。