java 操作excel的类_探究下Java操作Excel的几类工具

有骏奇
2023-12-01

引言

java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。

在做技术选择的时候,发现国内个人开发的eec与阿里开源的easyexcel有一比之力。

Easyexcel与EEC比较

1. Easyexcel

宗旨—— 快速、简单避免OOM的java处理Excel工具。

Easyexcel是阿里巴巴的一个开源项目,权威性不用多说,号称64M内存1分钟内读取75M(46W行25列)的Excel,并且急速模式能更快(代价就是会耗费更多的内存)。

easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到几M,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式,在上层做了模型转换的封装,让使用者更加简单方便。

背靠阿里,知名度高,目前国内使用较多。

2. EEC

宗旨 —— 一个高效、低内存支持GB级别Excel读写工具,非POI底层支持流式读取。

EEC(Excel Export Core)是一个Excel读取和写入工具,目前支持xlsx格式的读取、写入以及xls格式的读取(xls支持版本BIFF8也就是excel 97~2003格式)。

与传统Excel操作工具不同之处在于EEC并不缓存或只少量缓存数据到内存,写文件时EEC使用分片来处理较大的数据,使用迭代模式读取Excel行内容,当你使用某行数据的时才去解析它们,而不会将整个文件读入到内存。

EEC最大特点是高速和低内存,如果在项目中做数据导入导出,选用EEC将为你带来极大的便利,同时它的可扩展能力也不弱。

EEC采用单线程、高IO设计,所以多核心、高内存并不能显著提高速度,高主频和一块好SSD能显著提升速度。

EEC并不是一个功能全面的Excel操作工具类,它功能有限并不能用它来完全替代Apache POI,它最擅长的操作是表格处理。比如将数据库表导出为Excel或者读取Excel表格内容到Stream或数据库。

实战

pom.xml主要依赖如下:

com.alibaba

easyexcel

1.1.2-beat1

org.ttzero

eec

0.4.6

org.projectlombok

lombok

1.18.2

1. easyexcel读取和写入Excel

package Excel;

import java.io.*;

import java.util.ArrayList;

import java.util.List;

import com.alibaba.excel.EasyExcelFactory;

import com.alibaba.excel.ExcelReader;

import com.alibaba.excel.context.AnalysisContext;

import com.alibaba.excel.event.AnalysisEventListener;

import com.alibaba.excel.ExcelWriter;

import com.alibaba.excel.metadata.Sheet;

import com.alibaba.excel.support.ExcelTypeEnum;

/**

* 使用阿里巴巴开源的 easyexcel 进行Excel的读取与写入

* jar包版本为 1.1.2-beat1

* 相对 Apache poi、jxl能够加快速度并节省内存

*/

public class ExcelReadAndWrite {

private static String input = "src/main/java/Excel/easyexcel.xlsx";

private static String output = "src/main/java/Excel/easyexcel.xlsx";

/**

* 读取 Excel

*

* @throws Exception

*/

public static void read() {

try (InputStream in = new FileInputStream(input)) {

AnalysisEventListener> listener = new AnalysisEventListener>() {

@Override

public void invoke(List object, AnalysisContext context) {

// 打印每行数据

System.out.println(object);

}

@Override

public void doAfterAllAnalysed(AnalysisContext context) {

}

};

ExcelReader excelReader = EasyExcelFactory.getReader(in, listener);

excelReader.read();

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 写入Excel,支持 XLS 和 XLSX 两种格式

*

* @throws IOException

*/

public static long write() {

long start = 0;

try (OutputStream out = new FileOutputStream(output);) {

ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX);

Sheet sheet1 = new Sheet(1, 0);

sheet1.setSheetName("sheet1");

List> data = new ArrayList<>();

// 生成待写入的数据

for (int i = 0; i < 20 * 10000; i++) {

List item = new ArrayList<>();

for (int j = 0; j < 7; j++) {

item.add("Hello World!");

}

data.add(item);

}

// 添加表头

// List> head = new ArrayList<>();

// List headCoulumn1 = new ArrayList<>();

// headCoulumn1.add("第一列");

// head.add(headCoulumn1);

// Table table = new Table(1);

// table.setHead(head);

start = System.currentTimeMillis();

// 写入到文件

writer.write0(data, sheet1);

writer.finish();

} catch (IOException e) {

e.printStackTrace();

}

return start;

}

public static void main(String[] args) {

long start = System.currentTimeMillis();

read();

long end = System.currentTimeMillis();

System.out.println("读取耗时" + (end - start) + "ms");

start = write();

end = System.currentTimeMillis();

System.out.println("写入耗时" + (end - start) + "ms");

}

}

2. eec读取和写入excel

相比easyexcel来说,eec在内存和速度上都是占优势的,但由于是个人开发的,可能测试覆盖率并不是很高,也许有未知BUG。

package Excel;

import lombok.Data;

import org.ttzero.excel.entity.ListSheet;

import org.ttzero.excel.entity.Workbook;

import org.ttzero.excel.reader.ExcelReader;

import org.ttzero.excel.reader.Row;

import org.ttzero.excel.reader.Sheet;

import java.io.IOException;

import java.nio.file.Paths;

import java.util.ArrayList;

import java.util.Iterator;

import java.util.List;

/**

* EEC读取与写入Excel

* 参考

* https://www.ttzero.org/excel/2020/03/03/eec-vs-easyexcel.html EEC vs easyexcel

*/

@Data

class SelfData {

private String a;

private String b;

private String c;

private String d;

private String e;

private String f;

private String g;

}

public class EECOpe {

private static String input = "src/main/java/Excel/Large_EEC.xlsx";

private static String output = "src/main/java/Excel";

/**

* 使用iterator遍历所有行

*/

public static void read() {

try (ExcelReader reader = ExcelReader.read(Paths.get(input))) {

Sheet sheet = reader.sheet(0);

Iterator ite = sheet.iterator();

// 迭代遍历

while (ite.hasNext()) {

System.out.println(ite.next());

}

// 流式处理

// reader.sheets().flatMap(Sheet::rows).forEach(System.out::println);

} catch (IOException e) {

e.printStackTrace();

}

}

public static List data() {

List list = new ArrayList<>();

for (int i = 0; i < 1000; i++) {

SelfData largeData = new SelfData();

list.add(largeData);

largeData.setA("Hello World");

largeData.setB("Hello World");

largeData.setC("Hello World");

largeData.setD("Hello World");

largeData.setE("Hello World");

largeData.setF("Hello World");

largeData.setG("Hello World");

}

return list;

}

public static long write() {

long start = System.currentTimeMillis();

try {

new Workbook("Large_EEC").addSheet(new ListSheet() {

int n = 0;

@Override

public List more() {

return n++ < 200 ? data() : null;

}

}).writeTo(Paths.get(output));

} catch (IOException e) {

e.printStackTrace();

}

return start;

}

public static void main(String[] args) {

long start = System.currentTimeMillis();

System.out.println(start);

read();

long end = System.currentTimeMillis();

System.out.println("读取耗时" + (end - start) + "ms");

start = write();

end = System.currentTimeMillis();

System.out.println("写入耗时" + (end - start) + "ms");

}

}

若读取出来后不进行打印,总体时间还会进一步缩短。

性能方面,有人测试的结果是 ——读和写EEC都是easyexcel的一到两倍。

小结

总的来说,对内存和速度有一定要求并且求稳,就使用阿里巴巴开源的easyexcel。若对速度有更高的要求,则选择EEC。

参考

 类似资料: