POI与EasyExcel
简介
使用java语言实现大数据的读写操作 --> .excel文件
例如:
- 用户信息导出
- excel文件导入到网站数据库
- 数据处理。。。
主流工具
- Appache POI
- easyExcel
Appache POI
概述
Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能。
官网: https://poi.apache.org/
基本功能:
- HSSF- 提供读写Microsoft Excel XLS格式档案的功能。2003
- XSSF- 提供读写Microsoft Excel OOXML XLSX格式档案的功能。2007
- HWPF - 提供读写Microsoft Word DOC格式档案的功能。
- HSLF- 提供读写Microsoft PowerPoint格式档案的功能。
- HDGF- 提供读Microsoft Visio格式档案的功能。
- HPBF- 提供读Microsoft Publisher格式档案的功能。
-
HSMF- 提供读Microsoft Outlook格式档案的功能。
依赖
<!--poi-xls 03版操作-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.0.0</version>
</dependency>
<!--poi-xlsx 07版操作-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.0.0</version>
</dependency>
<!--日期格式化工具-->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.10.10</version>
</dependency>
写
xls格式与xls格式区别是工作簿对象不同
@Test
void contextLoads() throws Exception {
//1.创建工作簿
HSSFWorkbook sheets1 = new HSSFWorkbook();//03
XSSFWorkbook sheets = new XSSFWorkbook();//07
//2.创建工作表
XSSFSheet work1 = sheets.createSheet("work1");
//3.创建行
XSSFRow row = work1.createRow(0);
//4.创建单元格
XSSFCell cell01 = row.createCell(0);
//单元格赋值
cell01.setCellValue("值");
String time = new DateTime().toString("yyyy-MMMM-dd HH:mm:ss");
work1.createRow(1).createCell(1).setCellValue(time);
//生成表
//格式规范 new XSSFWorkbook()以 .xlsx 结尾
FileOutputStream fileOutputStream = new FileOutputStream("F:\\Desktop\\笔记\\test.xlsx");
sheets.write(fileOutputStream);
fileOutputStream.close();//关闭流
}
注意
- HSSFWorkbook 数据最多只能处理65535行,超出报异常,受excel版本限制。 优势:速度较快
- XSSFWorkbook 数据无限制,但写数据速度慢,非常耗用内存资源,可能会发生内存溢出。 优势:可以写较大的数据量
- SXSSFWorkbook 大数据量的流式版本 写数据速度块,占用内存少
- 过程中会产生临时文件,需要清理
- 内存中保留100条数据,超过100条最前面数据写入临时文件 可以在构造时自定义内存中保留数据
@Test
void test2() throws Exception{
SXSSFWorkbook sheets = new SXSSFWorkbook();
SXSSFSheet sheet = sheets.createSheet();
for (int i = 0; i < 50000; i++) {
SXSSFRow row = sheet.createRow(i);
for (int j = 0; j < 10; j++) {
SXSSFCell cell = row.createCell(j);
cell.setCellValue(i + " " + j);
}
}
FileOutputStream fileOutputStream = new FileOutputStream("F:\\Desktop\\笔记\\test.xlsx");
sheets.write(fileOutputStream);
sheets.dispose();//清除临时文件
fileOutputStream.close();//关闭流
}
5.0版本 write()方法增加了自动删除临时文件
@Override
public void write(OutputStream stream) throws IOException {
flushSheets();
//Save the template
File tmplFile = TempFile.createTempFile("poi-sxssf-template", ".xlsx");
boolean deleted;
try {
try (FileOutputStream os = new FileOutputStream(tmplFile)) {
_wb.write(os);
}
//Substitute the template entries with the generated sheet data files
try (ZipSecureFile zf = new ZipSecureFile(tmplFile);
ZipFileZipEntrySource source = new ZipFileZipEntrySource(zf)) {
injectData(source, stream);
}
} finally {
deleted = tmplFile.delete();//<===here
}
if(!deleted) {
throw new IOException("Could not delete temporary file after processing: " + tmplFile);
}
}
读
.xls
@Test
void readTest2() throws Exception {
FileInputStream fileInputStream = new FileInputStream("F:\\Desktop\\笔记\\test.xls");
HSSFWorkbook sheets = new HSSFWorkbook(fileInputStream);
HSSFSheet test = sheets.getSheet("test");//HSSFSheet sheetAt = sheets.getSheetAt(0);
System.out.println(test.getRow(0).getCell(0).getStringCellValue());
fileInputStream.close();
}
getStringCellValue(): 获取字符串类型
读取时要注意数据类型,不一致抛出异常 IllegalStateException
.xlsx
@Test
void readTest1() throws Exception {
FileInputStream fileInputStream = new FileInputStream("F:\\Desktop\\笔记\\test.xlsx");
XSSFWorkbook sheets = new XSSFWorkbook(fileInputStream);
XSSFSheet test = sheets.getSheet("test");//sheets.getSheetAt(0)
System.out.println(test.getRow(0).getCell(0).getRawValue());
System.out.println(test.getRow(1).getCell(0).getRawValue());
fileInputStream.close();
}
读取不同的数据类型
@Test
void readTest3() throws Exception {
FileInputStream fileInputStream = new FileInputStream("F:\\Desktop\\笔记\\test.xlsx");
XSSFWorkbook sheets = new XSSFWorkbook(fileInputStream);
XSSFSheet test = sheets.getSheetAt(0);
int rowCount = test.getPhysicalNumberOfRows();
for (int i = 0; i < rowCount; i++) {
Row row = test.getRow(i);
if (row != null) {
int cellCount = row.getPhysicalNumberOfCells();//数目
for (int j = 0; j < cellCount; j++) {
Cell cell = row.getCell(j);
if (cell != null) {
CellType cellType = cell.getCellType();
//方式一: toString() 统一转换成string类型
//System.out.println(cell);
//方式二: 逐个比较
Object value = null;
switch (cellType) {
case STRING://字符串
value = cell.getStringCellValue();
break;
case BOOLEAN://布尔值
value = cell.getBooleanCellValue();
break;
case NUMERIC://数字类型
//日期类型
if (DateUtil.isCellDateFormatted(cell)) {
value = new DateTime(cell.getDateCellValue());
break;
}
value = cell.getNumericCellValue();
break;
case FORMULA://公式计算
XSSFFormulaEvaluator formulaEvaluator = new XSSFFormulaEvaluator(sheets);//获取公式
value = formulaEvaluator.evaluate(cell).getNumberValue();
break;
case ERROR://错误
System.out.println("数据类型错误");
case BLANK://空值
break;
default:
value = "";
}
System.out.println(value);
}
}
}
}
fileInputStream.close();
}
计算公式
XSSFFormulaEvaluator formulaEvaluator = new XSSFFormulaEvaluator(sheets);//获取公式
CellValue evaluate = formulaEvaluator.evaluate(cell);//计算
double numberValue = evaluate.getNumberValue(); //获取数据类型
EasyExcel
概述
官网: https://gitee.com/Lancekkp/easyexcel
JAVA解析Excel工具EasyExcel
EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。
EasyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行行读取数据,逐个解析。
easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到几M,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便
依赖
<!-- easyexcel -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.10</version>
</dependency>
基于poi 3.17 版本
基本使用
写入对象
@Data
public class Demo {
@ExcelProperty("字符传")//自定义头部
private String string;
@ExcelProperty("数字")
private int num;
@ExcelProperty("日期标题")
private Date date;
private double aDouble;
@ExcelIgnore//写入时忽视
private String te;
public static List<Demo> data() {
List<Demo> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Demo data = new Demo();
data.setString("字符串" + i);
data.setDate(new Date());
data.setADouble(0.56);
list.add(data);
}
return list;
}
}
简单写入
@Test
void test01() {
disableWarning();
String fileName = "F:\\Desktop\\笔记\\" + "simpleWrite.xlsx";
EasyExcel.write(fileName, Demo.class).sheet("模板").doWrite(Demo.data());
}
write(文件导出目录,格式类)
sheet(表名)
doWrite(数据<List集合>)
读取
需要读取监听类
public class DemoDataListener extends AnalysisEventListener<Demo> {
List<Demo> list = new ArrayList<>();
//每一条数据解析都会来调用
@Override
public void invoke(Demo data, AnalysisContext context) {
System.out.println(JSON.toJSONString(data));//fastjson解析
list.add(data);
}
//当所有数据都被解析后,调用该方法
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
System.out.println("解析完成");
System.out.println(list);
}
}
注意:DemoDataListener 不能被spring管理,每次读取excel都要new
简单读取
@Test
void test02(){
disableWarning();
String fileName = "F:\\Desktop\\笔记\\" + "simpleWrite.xlsx";
EasyExcel.read(fileName,Demo.class,new DemoDataListener()).sheet().doRead();
}
总结
相对来说,easyExcel使用更简单,对对象处理较好;poi更灵活,最新版体验较好,可以通过封装使用