在上篇博客中 向大家介绍了什么是POI,以及如何用POI来处理Excel文件。具体可以查看上篇博客 POI的介绍及如何使用
在熟练掌握POI后,我们知道HSSF以及XSSF都基于DOM内存来读写文件,如果遇到较大数据时(比如 Row=10000时, 我们将使用WorkBook的SXSSF实现类来处理大数据文件。
FileOutputStream fos = new FileOutputStream("D:\\tupian\\data1.xlsx");
Workbook wbk = new SXSSFWorkbook();//实现Workbook的SXSSF实现类
wbk.write(fos); //写入Excel文件
本篇我们要介绍关于Alibaba开源的EasyExcel,通过EasyExcel来处理超大文件
在使用EasyExcel时我们首先应当准备实体类,这里我们准备了Order类作为实体类
package com.my.hyz;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.NumberFormat;
public class Order {
@ExcelProperty("订单编号")
private String orderId; // 订单编号
@ExcelProperty("支付金额")
@NumberFormat("¥#,###")
private Double payment; // 支付金额
@ExcelProperty(value = "创建日期",converter = LocalDateTimeConverter.class)
private LocalDateTime creationTime; // 创建时间
public Order() {
this.orderId = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddhhmmss"))
+ UUID.randomUUID().toString().substring(0, 5);
this.payment = Math.random() * 10000;
this.creationTime = LocalDateTime.now();
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public Double getPayment() {
return payment;
}
public void setPayment(Double payment) {
this.payment = payment;
}
public LocalDateTime getCreationTime() {
return creationTime;
}
public void setCreationTime(LocalDateTime creationTime) {
this.creationTime = creationTime;
}
@Override
public String toString() {
return "Order [orderId=" + orderId + ", payment=" + payment + ", creationTime=" + creationTime + "]";
}
}
特别的是,在我们实现创建时间时需要调用LocalDateTimeConverter转换类实现LocalDateTime日期时间的转换。因此我们需要提前准备converter转换类。
public class LocalDateTimeConverter implements Converter {
@Override
public Class supportJavaTypeKey() {
return LocalDateTime.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
@Override
public LocalDateTime convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return LocalDateTime.parse(cellData.getStringValue(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
@Override
public CellData convertToExcelData(LocalDateTime value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
return new CellData<>(value.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
}
}
在准备完毕后 我们就可以把100万行数据写入Excel。
package com.my.hyz;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.excel.EasyExcel;
public class Demo01 {
public static void main(String[] args) {
// 写入100w
long begin = System.currentTimeMillis();
EasyExcel.write("D:\\tupian\\100w.xlsx", Order.class)
.sheet("订单列表")
.doWrite(data());
long end = System.currentTimeMillis();
long time = end-begin;
System.out.println("写入文件时间为:"+time);
}
// 创建100w条订单数据
private static List data() {
List list = new ArrayList();
for (int i = 0; i < 1000000; i++) {
list.add(new Order());
}
return list;
}
}
这里我们输出了写入文件的时间,由图可知写入文件的时间是19787
若要用POI提供的SXSSF写入。
package com.my.hyz5;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.DataFormat;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
public class Demo09 {
public static void main(String[] args) {
try {
List list = new ArrayList(Arrays.asList("1","2","3","4","5","6"));
//FileInputStream fis = new FileInputStream("D:\\tupian\\data.xlsx");
FileOutputStream fos = new FileOutputStream("D:\\tupian\\data1.xlsx");
Workbook wbk = new SXSSFWorkbook(1000);
Sheet sheet01 = wbk.createSheet();
//獲取編碼值格式
DataFormat dataeFormat = wbk.createDataFormat();
short dataFormatCode = dataeFormat.getFormat("yyyy年MM月dd日 HH:mm:ss");
short moneyFormatCode = dataeFormat.getFormat("$#,###");
//创建一个日期格式对象
CellStyle datecellStyle = wbk.createCellStyle();
datecellStyle.setDataFormat(dataFormatCode);
//创建货币对象
CellStyle moneycellStyle = wbk.createCellStyle();
moneycellStyle.setDataFormat(moneyFormatCode);
long begin = System.currentTimeMillis();
for(int i =0 ;i<1000000;i++) {
String name = i+"A";
Row row1 = sheet01.createRow(i+1);
Cell cell0 = row1.createCell(0);
cell0.setCellValue(String.valueOf(i));//序号
Cell cell1 = row1.createCell(1);
cell1.setCellValue(name);//姓名
Cell cell2 = row1.createCell(2);//日期
cell2.setCellStyle(datecellStyle);
cell2.setCellValue(new Date());
Cell cell3 = row1.createCell(3);
cell3.setCellStyle(moneycellStyle);
cell3.setCellValue((int)(Math.random()*1000));
}
wbk.write(fos);
long end = System.currentTimeMillis();
long time = end-begin;
System.out.println("time"+time);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
时间为:
由此可知EasyExcel的时间略长于POI,但相差不多
在写入成功后,我们期望读取到Excel中的数据。
package com.my.hyz;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
public class Demo02 {
public static void main(String[] args) {
List orderList = new ArrayList();
EasyExcel.read("D:\\tupian\\100w.xlsx", Order.class,new AnalysisEventListener() {
@Override
public void invoke(Order order, AnalysisContext arg1) {
// 读取每条数据
orderList.add(order);
}
@Override
public void invokeHeadMap(Map headMap, AnalysisContext context) {
// 读取到列头
System.out.println(headMap);
}
@Override
public void doAfterAllAnalysed(AnalysisContext arg0) {
// 读取完毕
System.out.println("END");
}
}).sheet().doRead();
//遍历list
for(Order order :orderList) {
System.out.println(order);
}
}
}
结果为:
由于控制台Console显示有限,因此无法输出Excel中的全部数据。
那么如果我们用POI来读取这个Row为100W的Excel会出现什么情况呢。
package com.my.hyz5;
import java.io.FileInputStream;
import java.io.IOException;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
public class Demo08 {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("D:\\tupian\\100w.xlsx");
Workbook wbk = new XSSFWorkbook(fis)) {
Sheet sheet01 = wbk.getSheetAt(0);
//列头
Row row = sheet01.getRow(0);
for(Cell c1 :row) {
System.out.print(c1.getStringCellValue()+"\t");
}
System.out.println();
//数据行
for(int i =1 ;i
结果电脑变得卡顿CPU占用率也达到峰值,仍然无法读取出结果。
由此证明 当我们读取超大Excel文件时,应当采用更高效的EasyExcel。