作为一个常常进行数据分析的后端人员,免不了面临各种报表,且在日常的作业中,常常需求处理很多的数据,并进行各种杂乱的计算和分析。而Excel作为一个重要的东西,在数据处理与分析上也起到了至关重要的作用。但是,Excel的操作繁琐、功率低劣等问题也制约着咱们的作业功率。为了处理这个问题,咱们可以运用EasyExcel这个优异的Java类库,来优化Excel数据的读写,并进步咱们的作业功率。在本文中,我将向咱们介绍怎么运用EasyExcel的高效技巧,然后更好地搞定Excel繁琐操作。
一、EasyExcel简介
EasyExcel是一个根据Java的、快速、简练、处理大文件内存溢出的Excel处理东西。
他能让你在不用考虑功能、内存的等因素的情况下,快速完结Excel的读、写等功能。
EasyExcel是一个根据POI封装的Java类库,它可以对Excel文件进行读写操作。EasyExcel简略易用,功能优异,并且支撑很多的Excel操作。无论是简略的数据导入仍是杂乱的数据处理和导出,EasyExcel都可以轻松完成。一起,EasyExcel也支撑多种数据格局,包括Excel、CSV、TSV等。EasyExcel底层运用反射完成,因此也支撑泛型。EasyExcel已被广泛应用于各种项目中,成为Java开发者优化Excel操作的首选库之一。
16M内存23秒读取75M(46W行25列)的Excel(3.2.1+版本)
- 官方网站:easyexcel.opensource.alibaba.com
- github地址:github.com/alibaba/eas…
- gitee地址:gitee.com/easyexcel/e…
二、EasyExcel的高效技巧
1. 读取Excel文件
在日常作业中,读取Excel文件是咱们常常会遇到的需求之一。EasyExcel供给了多种读取Excel文件的办法,包括读取指定Sheet、读取指定列等。下面是一个简略的代码示例:
//读取指定Sheet
List<YourModelName> list = EasyExcel.read(fileName)
.sheet(sheetNo)
.head(YourModelName.class)
.doReadSync();
//读取指定列
List<Object> list = EasyExcel.read(fileName)
.sheet(sheetNo)
.headRow(rowNo)
.readRowFilter(new ReadRowFilter() {
@Override
public boolean doFilter(List<Object> list) {
if (list.get(0).equals("某一列的值")) {
return true;
}
return false;
}
})
.doReadSync();
2. 写入Excel文件
除了读取Excel文件外,咱们在实践作业中也需求频繁地向Excel文件中写入数据。EasyExcel供给了多种写入Excel文件的办法,包括向指定Sheet写入数据、向指定行写入数据、动态兼并单元格等。下面是一个简略的代码示例:
//向指定Sheet写入数据
ExcelWriter excelWriter = null;
try {
excelWriter = EasyExcel.write(fileName, YourModelName.class).build();
WriteSheet writeSheet = EasyExcel.writerSheet(sheetNo).build();
excelWriter.write(dataList, writeSheet);
} finally {
if (excelWriter != null) {
excelWriter.finish();
}
}
//向指定行写入数据
ExcelWriter excelWriter = null;
try {
excelWriter = EasyExcel.write(fileName, YourModelName.class).build();
WriteSheet writeSheet = EasyExcel.writerSheet(sheetNo).build();
excelWriter.write(dataList, writeSheet, new WriteTable()) .relativeHeadRowIndex(rowNo) .doWrite();
} finally {
if (excelWriter != null) {
excelWriter.finish();
}
}
3. 填充Excel
在实践作业中,咱们也常常需求对Excel文件进行填充。EasyExcel供给了多种填充Excel的办法,包括目标填充、自界说填充等。下面是一个简略的代码示例:
//目标填充
List<YourModelName> dataList = getDataList();
OutputStream outputStream = new FileOutputStream(fileName);
EasyExcel.write(outputStream, YourModelName.class)
.sheet(sheetNo)
.doWrite(dataList);
outputStream.close();
//自界说填充
List<Object> headList = getHeadList();
List<List<Object>> dataList = getDataList();
ExcelWriter excelWriter = null;
try {
excelWriter = EasyExcel.write(fileName).build();
WriteSheet writeSheet = EasyExcel.writerSheet(sheetNo).build();
FillConfig fillConfig = FillConfig.builder().direction(WriteDirectionEnum.VERTICAL).build();
excelWriter.fill(headList, fillConfig, writeSheet);
excelWriter.fill(dataList, fillConfig, writeSheet);
} finally {
if (excelWriter != null) {
excelWriter.finish();
}
}
4. 留意事项
在运用EasyExcel进行Excel操作时,咱们也需求留意一些细节问题。下面是一些需求留意的事项:
- EasyExcel默认对读取到的单元格内容进行trim操作,因此假如需求保留前后空格需求手动设置。
//禁止EasyExcel对单元格内容进行trim操作
Object value = cell.getStringCellValue();
cell.setCellValue(new HSSFRichTextString(value.toString()));
- 假如需求读取很多数据,可以运用异步读取的办法,进步读取功率。
//异步读取
EasyExcel.read(fileName, YourModelName.class, new ReadListener<YourModelName>() {
// 重写办法
}).sheet().doRead();
5. 内部中心源码分析
EasyExcel的底层代码完成是根据POI完成的,在POI的基础上又进一步进行了封装。详细来说,EasyExcel是经过反射来完成Excel文件的读写操作的,它利用了Java的泛型机制、注解等来完成高效简练的Excel操作。EasyExcel底层的完成思路比较简略,咱们可以经过阅览其源码来更好地理解其完成原理,然后更好地应用EasyExcel进行Excel数据的读写操作。
EasyExcel的底层代码完成主要根据Apache POI(Poor Obfuscation Implementation)和Java反射机制,其间Apache POI是一个支撑Microsoft Office格局的Java类库,可以完成对Excel、Word、PowerPoint等文档格局的读写操作。EasyExcel利用了POI供给的接口来读写Excel文件,并在此基础上进行了封装和优化,以进步读写功率。
EasyExcel的数据读取主要触及以下过程:
-
创立Workbook目标,翻开Excel文件,获取Sheet目标;
-
根据Sheet目标获取行和列目标,然后遍历Excel文件中的一切数据单元格;
-
经过反射机制将数据单元格中的值赋值给Java目标中的特点,最终得到完好的Java目标;
-
将Java目标添加到List调集中并回来。
EasyExcel的数据写入主要触及以下过程:
-
创立Workbook目标,创立Sheet目标;
-
遍历要写入的Java目标调集,将每个特点值写入Excel文件对应的单元格中;
-
加锁操作,将数据持久化到磁盘中。
在实践代码完成过程中,EasyExcel还采用了一些技能手段来进步功能和易用性:
-
运用线程池技能并发读写,多线程带来了更高的并发度,进步了读写功率。
-
缓存读取数据,将读取到的数据先缓存起来,再进行批量处理,大大进步了数据读取功率。
-
运用缓存技能,缓存Workbook、Sheet等目标,防止重复创立和毁掉目标,然后进步运转功率。
-
利用Java的泛型机制和注解技能进行简练的编程完成,减少了代码的冗余度,使代码愈加易于维护和扩展。
EasyExcel的底层完成离不开Apache POI和Java反射机制,经过这些技能的应用,EasyExcel完成了对Excel文件的高效读写操作。
EasyExcel的中心源码完成主要触及到以下几个方面:
1.运用POI进行Excel文件的读取和写入,POI供给了SXSSF等优化机制来进步读写功率。
2.采用反射机制主动将Excel中的数据映射为Java目标,并进行类型转化等操作。
3.运用注解来为Java目标中的特点和Excel中的表头进行映射,例如@ExcelProperty注解用于符号Java目标中的特点是Excel中的第几列。
4.运用缓存技能对Workbook、Sheet等目标进行缓存,防止重复创立和毁掉目标,进步运转功率。
下面咱们来详细看一下EasyExcel源码中的注解部分:
- @ExcelProperty注解
@ExcelProperty注解用于符号Java目标中的特点是Excel中的第几列。该注解包括三个特点:index、value和converter。
-
index特点表明Java目标中的特点在Excel中对应的列的索引,默认值为-1,表明主动匹配。假如该值设置为2,则表明该特点与Excel中第3列对应。
-
value特点表明Excel中该列的表头称号。假如设置了该值,则Excel中该列的表头称号为value的值;假如未设置,则默认为该特点的称号或字段称号。
-
converter特点表明数据类型转化器,可将Excel文件中的数据进行类型转化。例如,当Excel中的数据为字符串时可以经过设置converter特点将其转化为指定的数据类型。
- @ExcelIgnore注解
@ExcelIgnore注解用于符号Java目标中不需求映射为Excel中的列的特点。运用该注解后,EasyExcel将主动疏忽该特点,不对其进行映射。
- @ExcelPropertyRange注解
@ExcelPropertyRange注解用于符号Excel文件中某个列的取值规模。该注解包括两个特点:min和max。假如Excel文件中该列的取值规模不符合要求,则EasyExcel会抛出异常。
- @ExcelHeadRowNumber注解
@ExcelHeadRowNumber注解用于符号Excel文件中表头地点的行号,默认为0,即第一行。假如设置为1,则表明表头在第二行。运用该注解可以灵活地装备表头地点的位置。
EasyExcel的主要中心源码触及到数据读取和写入两个方面,下面将别离进行详细的代码展现如下。
1. 数据读取
(1) ExcelReader类
首先来看ExcelReader类,它是EasyExcel中的中心类之一,用于读取Excel文件中的数据。以下是ExcelReader的界说:
public class ExcelReader<T> {
private static final Logger LOGGER = LoggerFactory.getLogger(ExcelReader.class);
private Sheet sheet;
private Workbook workbook;
private Class<T> currentSheetClazz;
// 省掉部分成员变量及构造办法
}
ExcelReader类包括了Sheet目标、Workbook目标和当时Sheet对应的Java类信息,这些信息在进行数据读取时都会用到。
(2) read(ReadSheet readSheet)办法
read(ReadSheet readSheet)办法是ExcelReader类中读取数据的中心办法,其界说如下:
public void read(ReadSheet readSheet) {
try {
readSheet.setClazz(currentSheetClazz);
readSheet.init();
process(readSheet);
} finally {
if (workbook != null) {
try {
workbook.close();
} catch (IOException e) {
LOGGER.warn("Close IO exception ,msg is {}", e.getMessage());
}
}
}
}
该办法首先将当时Sheet对应的Java类信息设置到读取装备ReadSheet中,然后初始化ReadSheet目标,并调用process办法进行数据读取。
(3) process(ReadSheet readSheet)办法
process(ReadSheet readSheet)办法是ExcelReader中最中心的数据读取办法,其界说如下:
private void process(ReadSheet readSheet) {
// 从Excel文件中读取一切的数据行
List<List<String>> rows = readSheet.getHead() == null ? sheet2List() : sheet2List(readSheet.getStartSheetIndex(), readSheet.getEndSheetIndex());
// 获取Java类中用于映射Excel中数据的特点列表
List<Field> fieldList = ReflectionUtil.getFieldListWithExcelColumn(currentSheetClazz);
// 缓存读取到的Java目标列表
List<T> dataList = new ArrayList<>();
if (CollectionUtils.isEmpty(rows)) {
return;
}
// 遍历Excel文件中每一行数据,将每一行数据映射为Java目标并添加到dataList中
for (int i = readSheet.getHead().getRowIndex(); i < rows.size(); i++) {
List<String> row = rows.get(i);
T data = ReflectionUtil.newInstance(currentSheetClazz);
for (int j = 0; j < fieldList.size(); j++) {
Field field = fieldList.get(j);
ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);
int index = excelProperty.index();
if (index >= row.size()) {
continue;
}
String value = row.get(index);
ReflectionUtil.setFieldValue(field, data, value);
}
dataList.add(data);
}
// 将读取到的数据回来给调用方
readSheet.getResultList().addAll(dataList);
}
该办法首先经过sheet2List办法将Excel文件中的每一行数据读取到List<List>类型的rows调集中,然后经过反射机制将Excel中的数据映射为Java目标并添加到dataList中,最终将dataList回来给调用方。
(4) sheet2List办法
sheet2List办法是ExcelReader类中的一个私有办法,用于将Excel文件中的一切数据读取到List<List>类型的rows调集中。以下是sheet2List办法的完成:
private List<List<String>> sheet2List() {
// 从Sheet中获取一切行
int rownum = sheet.getLastRowNum();
List<List<String>> rows = new ArrayList<>(rownum);
for (int i = sheet.getFirstRowNum(); i <= rownum; i++) {
Row row = sheet.getRow(i);
if (null == row) {
continue;
}
List<String> cells = new ArrayList<>(row.getLastCellNum());
for (int j = row.getFirstCellNum(); j < row.getLastCellNum(); j++) {
Cell cell = row.getCell(j, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
String cellValue = ExcelUtil.getCellValue(cell);
cells.add(cellValue);
}
rows.add(cells);
}
return rows;
}
该办法首先经过Sheet目标的getLastRowNum办法获取Excel文件中的总行数,然后遍历每一行数据,将每一行数据读取到List类型的cells调集中,并将一切行的数据添加到一个List<List>类型的rows调集中,最终回来rows调集。
2. 数据写入
(1) ExcelWriter类
ExcelWriter类是EasyExcel中的另一个中心类,用于写入数据到Excel文件中。以下是ExcelWriter类的界说:
public class ExcelWriter extends AbstractExcelWriter<WriteSheet> {
// 省掉部分代码及构造办法
}
ExcelWriter类承继自AbstractExcelWriter类,其主要作用是将WriteSheet目标中的数据写入到Excel文件中。
(2) write(List data, WriteSheet sheet)办法
write(List data, WriteSheet sheet)办法是ExcelWriter类中最中心的办法之一,它担任将Java目标调集data写入到Excel文件中。以下是write办法的界说:
public void write(List data, WriteSheet sheet) {
sheetHolder.set(sheet);
if (sheet == null) {
return;
}
sheet.init();
int index = sheetHolder.get().getIndex() == null ? 0 : sheetHolder.get().getIndex();
String sheetName = sheetHolder.get().getSheetName() == null ? "Sheet" + index : sheetHolder.get().getSheetName();
currentSheet = workbook.createSheet(sheetName);
write(data);
sheetHolder.remove();
}
该办法首先将当时的WriteSheet目标设置到sheetHolder中,并进行相应的初始化作业,然后创立一个新的Sheet目标,并将Java目标中的数据写入到该Sheet目标中,最终清空sheetHolder中的内容。
(3) write(List data)办法
write(List data)办法是ExcelWriter类中真正的数据写入办法,其界说如下:
private void write(List data) {
WriteHandler handler = sheetHolder.get().getWriteHandler();
if (handler != null && handler instanceof WorkbookHolder) {
((WorkbookHolder) handler).setWorkbook(workbook);
}
// 获取Java目标中用于映射Excel中数据的特点列表
List<Field> fieldList = ReflectionUtil.getFieldListWithExcelColumn(data.get(0).getClass());
// 设置Excel文件中的表头
setHead(handler, fieldList);
try {
// 遍历Java目标并将其写入到Excel文件中
for (int i = 0; i < data.size(); i++) {
Object rowModel = data.get(i);
setIndexValue(i + 1);
Row row = currentSheet.createRow(getRowIndex());
for (int j = 0; j < fieldList.size(); j++) {
Field field = fieldList.get(j);
if (needIgnore(j)) {
continue;
}
String stringValue = ReflectionUtil.getFieldStringValue(field, rowModel);
Cell cell = row.createCell(j);
if (handler != null && handler instanceof AbstractCellStyleStrategy) {
((AbstractCellStyleStrategy) handler).setCellStyle(cell, field, rowModel, getStringValue(stringValue));
}
CellData cellData = converterAndSet(cell, stringValue, field);
setCellComment(row, field, cellData);
}
}
} finally {
setIndexValue(null);
}
}
在该办法中,首先获取Java目标中用于映射Excel中数据的特点列表,并设置Excel文件中的表头。然后遍历Java目标并将其写入到Excel文件中,将Java目标中的每个特点值写入到Excel文件对应单元格中,并设置单元格款式、注释等信息。
三、小结一下
经过本文的简略介绍,信任咱们关于了解运用EasyExcel进行高效的Excel数据操作已经有了一个基础的入门知道。无论是读取Excel文件、写入Excel文件仍是填充Excel文件,EasyExcel都供给了非常简略、易用且高效的处理方案。在实践作业中,咱们可以结合本身的需求,选择不同的EasyExcel技巧来更好地完结任务。一起,咱们还需求留意一些细节问题,以确保Excel操作的正确性和功率。最终,我也期望咱们可以经过阅览本文,更好地掌握Springboot和EasyExcel的运用技巧,并在实践作业中得到应用,给详细的项目添砖加瓦~ v ~ v ~。