之前写过一篇《JAVA操作Excel》,介绍了jxl
和poi
读写Excel的实现,今天为大家介绍一下使用easyexcel
对Excel进行读写,项目主页地址:https://github.com/alibaba/easyexcel
作者对easyexcel的介绍是:
Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到KB级别,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便
使用easyexcel,首先我们需要添加maven依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>1.0.1</version>
</dependency>
首先,我们先来看看如何写Excel,写入Excel,我们可以通过com.alibaba.excel.ExcelWriter
类实现,下面我们来看一下最简单的无表头的实现
package test;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.support.ExcelTypeEnum;
public class ExcelWriteTest {
/**
* 每行数据是List<String>无表头
*
* @throws IOException
*/
@Test
public void writeWithoutHead() throws IOException {
try (OutputStream out = new FileOutputStream("withoutHead.xlsx");) {
ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX, false);
Sheet sheet1 = new Sheet(1, 0);
sheet1.setSheetName("sheet1");
List<List<String>> data = new ArrayList<>();
for (int i = 0; i < 100; i++) {
List<String> item = new ArrayList<>();
item.add("item0" + i);
item.add("item1" + i);
item.add("item2" + i);
data.add(item);
}
writer.write0(data, sheet1);
writer.finish();
}
}
}
生成的Excel样式如下:
很多时候,我们在生成Excel的时候都是需要添加表头的,使用easyexcel可以很容易的实现,我们可以对上面的例子进行简单的改造,为其添加表头
package test;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.metadata.Table;
import com.alibaba.excel.support.ExcelTypeEnum;
public class ExcelWriteTest {
@Test
public void writeWithoutHead() throws IOException {
try (OutputStream out = new FileOutputStream("withHead.xlsx");) {
ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX);
Sheet sheet1 = new Sheet(1, 0);
sheet1.setSheetName("sheet1");
List<List<String>> data = new ArrayList<>();
for (int i = 0; i < 100; i++) {
List<String> item = new ArrayList<>();
item.add("item0" + i);
item.add("item1" + i);
item.add("item2" + i);
data.add(item);
}
List<List<String>> head = new ArrayList<List<String>>();
List<String> headCoulumn1 = new ArrayList<String>();
List<String> headCoulumn2 = new ArrayList<String>();
List<String> headCoulumn3 = new ArrayList<String>();
headCoulumn1.add("第一列");
headCoulumn2.add("第二列");
headCoulumn3.add("第三列");
head.add(headCoulumn1);
head.add(headCoulumn2);
head.add(headCoulumn3);
Table table = new Table(1);
table.setHead(head);
writer.write0(data, sheet1, table);
writer.finish();
}
}
}
效果如下:
除了上面添加表头的方式,我们还可以使用实体类,为其添加com.alibaba.excel.annotation.ExcelProperty
注解来生成表头,实体类数据作为Excel数据
package test;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.metadata.Table;
import com.alibaba.excel.support.ExcelTypeEnum;
public class ExcelWriteTest {
@Test
public void writeWithHead() throws IOException {
try (OutputStream out = new FileOutputStream("withHead.xlsx");) {
ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX);
Sheet sheet1 = new Sheet(1, 0, ExcelPropertyIndexModel.class);
sheet1.setSheetName("sheet1");
List<ExcelPropertyIndexModel> data = new ArrayList<>();
for (int i = 0; i < 100; i++) {
ExcelPropertyIndexModel item = new ExcelPropertyIndexModel();
item.name = "name" + i;
item.age = "age" + i;
item.email = "email" + i;
item.address = "address" + i;
item.sax = "sax" + i;
item.heigh = "heigh" + i;
item.last = "last" + i;
data.add(item);
}
writer.write(data, sheet1);
writer.finish();
}
}
public static class ExcelPropertyIndexModel extends BaseRowModel {
@ExcelProperty(value = "姓名", index = 0)
private String name;
@ExcelProperty(value = "年龄", index = 1)
private String age;
@ExcelProperty(value = "邮箱", index = 2)
private String email;
@ExcelProperty(value = "地址", index = 3)
private String address;
@ExcelProperty(value = "性别", index = 4)
private String sax;
@ExcelProperty(value = "高度", index = 5)
private String heigh;
@ExcelProperty(value = "备注", index = 6)
private String last;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSax() {
return sax;
}
public void setSax(String sax) {
this.sax = sax;
}
public String getHeigh() {
return heigh;
}
public void setHeigh(String heigh) {
this.heigh = heigh;
}
public String getLast() {
return last;
}
public void setLast(String last) {
this.last = last;
}
}
}
效果如下:
如果单行表头表头还不满足需求,没关系,还可以使用多行复杂的表头
package test;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.metadata.Table;
import com.alibaba.excel.support.ExcelTypeEnum;
public class ExcelWriteTest {
@Test
public void writeWithMultiHead() throws IOException {
try (OutputStream out = new FileOutputStream("withMultiHead.xlsx");) {
ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX);
Sheet sheet1 = new Sheet(1, 0, MultiLineHeadExcelModel.class);
sheet1.setSheetName("sheet1");
List<MultiLineHeadExcelModel> data = new ArrayList<>();
for (int i = 0; i < 100; i++) {
MultiLineHeadExcelModel item = new MultiLineHeadExcelModel();
item.p1 = "p1" + i;
item.p2 = "p2" + i;
item.p3 = "p3" + i;
item.p4 = "p4" + i;
item.p5 = "p5" + i;
item.p6 = "p6" + i;
item.p7 = "p7" + i;
item.p8 = "p8" + i;
item.p9 = "p9" + i;
data.add(item);
}
writer.write(data, sheet1);
writer.finish();
}
}
public static class MultiLineHeadExcelModel extends BaseRowModel {
@ExcelProperty(value = { "表头1", "表头1", "表头31" }, index = 0)
private String p1;
@ExcelProperty(value = { "表头1", "表头1", "表头32" }, index = 1)
private String p2;
@ExcelProperty(value = { "表头3", "表头3", "表头3" }, index = 2)
private String p3;
@ExcelProperty(value = { "表头4", "表头4", "表头4" }, index = 3)
private String p4;
@ExcelProperty(value = { "表头5", "表头51", "表头52" }, index = 4)
private String p5;
@ExcelProperty(value = { "表头6", "表头61", "表头611" }, index = 5)
private String p6;
@ExcelProperty(value = { "表头6", "表头61", "表头612" }, index = 6)
private String p7;
@ExcelProperty(value = { "表头6", "表头62", "表头621" }, index = 7)
private String p8;
@ExcelProperty(value = { "表头6", "表头62", "表头622" }, index = 8)
private String p9;
public String getP1() {
return p1;
}
public void setP1(String p1) {
this.p1 = p1;
}
public String getP2() {
return p2;
}
public void setP2(String p2) {
this.p2 = p2;
}
public String getP3() {
return p3;
}
public void setP3(String p3) {
this.p3 = p3;
}
public String getP4() {
return p4;
}
public void setP4(String p4) {
this.p4 = p4;
}
public String getP5() {
return p5;
}
public void setP5(String p5) {
this.p5 = p5;
}
public String getP6() {
return p6;
}
public void setP6(String p6) {
this.p6 = p6;
}
public String getP7() {
return p7;
}
public void setP7(String p7) {
this.p7 = p7;
}
public String getP8() {
return p8;
}
public void setP8(String p8) {
this.p8 = p8;
}
public String getP9() {
return p9;
}
public void setP9(String p9) {
this.p9 = p9;
}
}
}
效果如下:
怎么样,这些已经基本满足我们的日常需求了,easyexcel不仅支持上述几种形式,还支持在一个sheet中添加多个表
package test;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.metadata.Table;
import com.alibaba.excel.support.ExcelTypeEnum;
public class ExcelWriteTest {
@Test
public void writeWithMultiTable() throws IOException {
try (OutputStream out = new FileOutputStream("withMultiTable.xlsx");) {
ExcelWriter writer = new ExcelWriter(out, ExcelTypeEnum.XLSX);
Sheet sheet1 = new Sheet(1, 0);
sheet1.setSheetName("sheet1");
// 数据全是List<String> 无模型映射关系
Table table1 = new Table(1);
List<List<String>> data1 = new ArrayList<>();
for (int i = 0; i < 5; i++) {
List<String> item = new ArrayList<>();
item.add("item0" + i);
item.add("item1" + i);
item.add("item2" + i);
data1.add(item);
}
writer.write0(data1, sheet1, table1);
// 模型上有表头的注解
Table table2 = new Table(2);
table2.setClazz(MultiLineHeadExcelModel.class);
List<MultiLineHeadExcelModel> data2 = new ArrayList<>();
for (int i = 0; i < 5; i++) {
MultiLineHeadExcelModel item = new MultiLineHeadExcelModel();
item.p1 = "p1" + i;
item.p2 = "p2" + i;
item.p3 = "p3" + i;
item.p4 = "p4" + i;
item.p5 = "p5" + i;
item.p6 = "p6" + i;
item.p7 = "p7" + i;
item.p8 = "p8" + i;
item.p9 = "p9" + i;
data2.add(item);
}
writer.write(data2, sheet1, table2);
// 模型上没有注解,表头数据动态传入,此情况下模型field顺序与excel现实顺序一致
List<List<String>> head = new ArrayList<List<String>>();
List<String> headCoulumn1 = new ArrayList<String>();
List<String> headCoulumn2 = new ArrayList<String>();
List<String> headCoulumn3 = new ArrayList<String>();
headCoulumn1.add("第一列");
headCoulumn2.add("第二列");
headCoulumn3.add("第三列");
head.add(headCoulumn1);
head.add(headCoulumn2);
head.add(headCoulumn3);
Table table3 = new Table(3);
table3.setHead(head);
writer.write0(data1, sheet1, table3);
writer.finish();
}
}
public static class MultiLineHeadExcelModel extends BaseRowModel {
@ExcelProperty(value = { "表头1", "表头1", "表头31" }, index = 0)
private String p1;
@ExcelProperty(value = { "表头1", "表头1", "表头32" }, index = 1)
private String p2;
@ExcelProperty(value = { "表头3", "表头3", "表头3" }, index = 2)
private String p3;
@ExcelProperty(value = { "表头4", "表头4", "表头4" }, index = 3)
private String p4;
@ExcelProperty(value = { "表头5", "表头51", "表头52" }, index = 4)
private String p5;
@ExcelProperty(value = { "表头6", "表头61", "表头611" }, index = 5)
private String p6;
@ExcelProperty(value = { "表头6", "表头61", "表头612" }, index = 6)
private String p7;
@ExcelProperty(value = { "表头6", "表头62", "表头621" }, index = 7)
private String p8;
@ExcelProperty(value = { "表头6", "表头62", "表头622" }, index = 8)
private String p9;
public String getP1() {
return p1;
}
public void setP1(String p1) {
this.p1 = p1;
}
public String getP2() {
return p2;
}
public void setP2(String p2) {
this.p2 = p2;
}
public String getP3() {
return p3;
}
public void setP3(String p3) {
this.p3 = p3;
}
public String getP4() {
return p4;
}
public void setP4(String p4) {
this.p4 = p4;
}
public String getP5() {
return p5;
}
public void setP5(String p5) {
this.p5 = p5;
}
public String getP6() {
return p6;
}
public void setP6(String p6) {
this.p6 = p6;
}
public String getP7() {
return p7;
}
public void setP7(String p7) {
this.p7 = p7;
}
public String getP8() {
return p8;
}
public void setP8(String p8) {
this.p8 = p8;
}
public String getP9() {
return p9;
}
public void setP9(String p9) {
this.p9 = p9;
}
}
}
效果如下:
如果表头的样式不满足我们的需求,需要调整,我们可以使用com.alibaba.excel.metadata.TableStyle
定义我们需要的样式,然后调用table对象的setTableStyle
方法进行设置。
好了,到这里写入excel就基本介绍完了,下面我们就来看看如何读取excel,实际上现在的这个版本(1.0.1
)在读取的时候是有BUG的,读取03版的.xls
格式的excel正常,但是读取07版的.xlsx
版的excel就会出异常,原因是在解析的时候sheet临时文件路径拼装有误,下面是我针对这个版本修复后的实现,大家可以替换掉原包中的实现
package com.alibaba.excel.read;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import javax.xml.parsers.ParserConfigurationException;
import com.alibaba.excel.read.v07.RowHandler;
import com.alibaba.excel.read.v07.XmlParserFactory;
import com.alibaba.excel.read.v07.XMLTempFile;
import com.alibaba.excel.read.context.AnalysisContext;
import com.alibaba.excel.read.exception.ExcelAnalysisException;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.util.FileUtil;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.xmlbeans.XmlException;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbookPr;
import org.openxmlformats.schemas.spreadsheetml.x2006.main.WorkbookDocument;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
public class SaxAnalyserV07 extends BaseSaxAnalyser {
private SharedStringsTable sharedStringsTable;
private List<String> sharedStringList = new LinkedList<String>();
private List<SheetSource> sheetSourceList = new ArrayList<SheetSource>();
private boolean use1904WindowDate = false;
private final String path;
private File tmpFile;
private String workBookXMLFilePath;
private String sharedStringXMLFilePath;
public SaxAnalyserV07(AnalysisContext analysisContext) throws Exception {
this.analysisContext = analysisContext;
this.path = XMLTempFile.createPath();
this.tmpFile = new File(XMLTempFile.getTmpFilePath(path));
this.workBookXMLFilePath = XMLTempFile.getWorkBookFilePath(path);
this.sharedStringXMLFilePath = XMLTempFile.getSharedStringFilePath(path);
start();
}
@Override
protected void execute() {
try {
Sheet sheet = analysisContext.getCurrentSheet();
if (!isAnalysisAllSheets(sheet)) {
if (this.sheetSourceList.size() < sheet.getSheetNo() || sheet.getSheetNo() == 0) {
return;
}
InputStream sheetInputStream = this.sheetSourceList.get(sheet.getSheetNo() - 1).getInputStream();
parseXmlSource(sheetInputStream);
return;
}
int i = 0;
for (SheetSource sheetSource : this.sheetSourceList) {
i++;
this.analysisContext.setCurrentSheet(new Sheet(i));
parseXmlSource(sheetSource.getInputStream());
}
} catch (Exception e) {
stop();
throw new ExcelAnalysisException(e);
} finally {
}
}
private boolean isAnalysisAllSheets(Sheet sheet) {
if (sheet == null) {
return true;
}
if (sheet.getSheetNo() < 0) {
return true;
}
return false;
}
public void stop() {
FileUtil.deletefile(path);
}
private void parseXmlSource(InputStream inputStream) {
try {
ContentHandler handler = new RowHandler(this, this.sharedStringsTable, this.analysisContext,
sharedStringList);
XmlParserFactory.parse(inputStream, handler);
inputStream.close();
} catch (Exception e) {
try {
inputStream.close();
} catch (IOException e1) {
e1.printStackTrace();
}
throw new ExcelAnalysisException(e);
}
}
public List<Sheet> getSheets() {
List<Sheet> sheets = new ArrayList<Sheet>();
try {
int i = 1;
for (SheetSource sheetSource : this.sheetSourceList) {
Sheet sheet = new Sheet(i, 0);
sheet.setSheetName(sheetSource.getSheetName());
i++;
sheets.add(sheet);
}
} catch (Exception e) {
stop();
throw new ExcelAnalysisException(e);
} finally {
}
return sheets;
}
private void start() throws IOException, XmlException, ParserConfigurationException, SAXException {
createTmpFile();
unZipTempFile();
initSharedStringsTable();
initUse1904WindowDate();
initSheetSourceList();
}
private void createTmpFile() throws FileNotFoundException {
FileUtil.writeFile(tmpFile, analysisContext.getInputStream());
}
private void unZipTempFile() throws IOException {
FileUtil.doUnZip(path, tmpFile);
}
private void initSheetSourceList() throws IOException, ParserConfigurationException, SAXException {
this.sheetSourceList = new ArrayList<SheetSource>();
InputStream workbookXml = new FileInputStream(this.workBookXMLFilePath);
XmlParserFactory.parse(workbookXml, new DefaultHandler() {
@Override
public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException {
if (qName.toLowerCase(Locale.US).equals("sheet")) {
String name = null;
int id = 0;
for (int i = 0; i < attrs.getLength(); i++) {
if (attrs.getLocalName(i).toLowerCase(Locale.US).equals("name")) {
name = attrs.getValue(i);
}/** else if (attrs.getLocalName(i).toLowerCase(Locale.US).equals("r:id")) {
id = Integer.parseInt(attrs.getValue(i).replaceAll("rId", ""));
try {
InputStream inputStream = new FileInputStream(XMLTempFile.getSheetFilePath(path, id));
sheetSourceList.add(new SheetSource(id, name, inputStream));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
} **/
//应该使用sheetId属性
else if (attrs.getLocalName(i).toLowerCase(Locale.US).equals("sheetid")) {
id = Integer.parseInt(attrs.getValue(i));
try {
InputStream inputStream = new FileInputStream(XMLTempFile.getSheetFilePath(path, id));
sheetSourceList.add(new SheetSource(id, name, inputStream));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
}
}
});
workbookXml.close();
// 排序后是倒序,不符合实际要求
// Collections.sort(sheetSourceList);
Collections.sort(sheetSourceList, new Comparator<SheetSource>() {
@Override
public int compare(SheetSource o1, SheetSource o2) {
return o1.id - o2.id;
}
});
}
private void initUse1904WindowDate() throws IOException, XmlException {
InputStream workbookXml = new FileInputStream(workBookXMLFilePath);
WorkbookDocument ctWorkbook = WorkbookDocument.Factory.parse(workbookXml);
CTWorkbook wb = ctWorkbook.getWorkbook();
CTWorkbookPr prefix = wb.getWorkbookPr();
if (prefix != null) {
this.use1904WindowDate = prefix.getDate1904();
}
this.analysisContext.setUse1904WindowDate(use1904WindowDate);
workbookXml.close();
}
private void initSharedStringsTable() throws IOException, ParserConfigurationException, SAXException {
//因为sharedStrings.xml文件不一定存在,所以在处理之前增加判断
File sharedStringXMLFile = new File(this.sharedStringXMLFilePath);
if (!sharedStringXMLFile.exists()) {
return;
}
InputStream inputStream = new FileInputStream(this.sharedStringXMLFilePath);
//this.sharedStringsTable = new SharedStringsTable();
//this.sharedStringsTable.readFrom(inputStream);
XmlParserFactory.parse(inputStream, new DefaultHandler() {
@Override
public void characters(char[] ch, int start, int length) {
sharedStringList.add(new String(ch, start, length));
}
});
inputStream.close();
}
private class SheetSource implements Comparable<SheetSource> {
private int id;
private String sheetName;
private InputStream inputStream;
public SheetSource(int id, String sheetName, InputStream inputStream) {
this.id = id;
this.sheetName = sheetName;
this.inputStream = inputStream;
}
public String getSheetName() {
return sheetName;
}
public void setSheetName(String sheetName) {
this.sheetName = sheetName;
}
public InputStream getInputStream() {
return inputStream;
}
public void setInputStream(InputStream inputStream) {
this.inputStream = inputStream;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int compareTo(SheetSource o) {
if (o.id == this.id) {
return 0;
} else if (o.id > this.id) {
return 1;
} else {
return -1;
}
}
}
}
另外,使用easyexcel读取excel的时候需要设置excel的版本,但是有些时候我们无法预知excel的版本,所以个人感觉这样不是太好,所以模仿poi
写了一个用于获取com.alibaba.excel.ExcelReader
对象的工具类
package com.alibaba.excel.read;
import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
import org.apache.poi.EmptyFileException;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.poifs.filesystem.DocumentFactoryHelper;
import org.apache.poi.poifs.filesystem.NPOIFSFileSystem;
import org.apache.poi.util.IOUtils;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.read.context.AnalysisContext;
import com.alibaba.excel.read.event.AnalysisEventListener;
import com.alibaba.excel.support.ExcelTypeEnum;
public class ExcelReaderFactory {
/**
* @param in
* 文件输入流
* @param customContent
* 自定义模型可以在
* {@link AnalysisEventListener#invoke(Object, AnalysisContext) }
* AnalysisContext中获取用于监听者回调使用
* @param eventListener
* 用户监听
* @throws IOException
* @throws EmptyFileException
* @throws InvalidFormatException
*/
public static ExcelReader getExcelReader(InputStream in, Object customContent,
AnalysisEventListener<?> eventListener) throws EmptyFileException, IOException, InvalidFormatException {
// 如果输入流不支持mark/reset,需要对其进行包裹
if (!in.markSupported()) {
in = new PushbackInputStream(in, 8);
}
// 确保至少有一些数据
byte[] header8 = IOUtils.peekFirst8Bytes(in);
ExcelTypeEnum excelTypeEnum = null;
if (NPOIFSFileSystem.hasPOIFSHeader(header8)) {
excelTypeEnum = ExcelTypeEnum.XLS;
}
if (DocumentFactoryHelper.hasOOXMLHeader(in)) {
excelTypeEnum = ExcelTypeEnum.XLSX;
}
if (excelTypeEnum != null) {
return new ExcelReader(in, excelTypeEnum, customContent, eventListener);
}
throw new InvalidFormatException("Your InputStream was neither an OLE2 stream, nor an OOXML stream");
}
/**
* @param in
* 文件输入流
* @param customContent
* 自定义模型可以在
* {@link AnalysisEventListener#invoke(Object, AnalysisContext) }
* AnalysisContext中获取用于监听者回调使用
* @param eventListener
* 用户监听
* @param trim
* 是否对解析的String做trim()默认true,用于防止 excel中空格引起的装换报错。
* @throws IOException
* @throws EmptyFileException
* @throws InvalidFormatException
*/
public static ExcelReader getExcelReader(InputStream in, Object customContent,
AnalysisEventListener<?> eventListener, boolean trim)
throws EmptyFileException, IOException, InvalidFormatException {
// 如果输入流不支持mark/reset,需要对其进行包裹
if (!in.markSupported()) {
in = new PushbackInputStream(in, 8);
}
// 确保至少有一些数据
byte[] header8 = IOUtils.peekFirst8Bytes(in);
ExcelTypeEnum excelTypeEnum = null;
if (NPOIFSFileSystem.hasPOIFSHeader(header8)) {
excelTypeEnum = ExcelTypeEnum.XLS;
}
if (DocumentFactoryHelper.hasOOXMLHeader(in)) {
excelTypeEnum = ExcelTypeEnum.XLSX;
}
if (excelTypeEnum != null) {
return new ExcelReader(in, excelTypeEnum, customContent, eventListener, trim);
}
throw new InvalidFormatException("Your InputStream was neither an OLE2 stream, nor an OOXML stream");
}
}
下面我们就来写一个简单的读取Excel的示例:
package test;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.List;
import org.junit.Test;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.read.ExcelReaderFactory;
import com.alibaba.excel.read.context.AnalysisContext;
import com.alibaba.excel.read.event.AnalysisEventListener;
public class ExcelReadTest {
@Test
public void read() throws Exception {
try (InputStream in = new FileInputStream("withoutHead.xlsx");) {
AnalysisEventListener<List<String>> listener = new AnalysisEventListener<List<String>>() {
@Override
public void invoke(List<String> object, AnalysisContext context) {
System.err.println("Row:" + context.getCurrentRowNum() + " Data:" + object);
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
System.err.println("doAfterAllAnalysed...");
}
};
ExcelReader excelReader = ExcelReaderFactory.getExcelReader(in, null, listener);
excelReader.read();
}
}
}
正如写入Excel的时候可以使用数据模型一样,在读取Excel的时候也可以直接将数据映射为模型对象,区别在于要使用ExcelReader #read
的重载方法。
package test;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.List;
import org.junit.Test;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.metadata.BaseRowModel;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.read.ExcelReaderFactory;
import com.alibaba.excel.read.context.AnalysisContext;
import com.alibaba.excel.read.event.AnalysisEventListener;
public class ExcelReadTest {
@Test
public void read() throws Exception {
try (InputStream in = new FileInputStream("withHead.xlsx");) {
AnalysisEventListener<ExcelPropertyIndexModel> listener = new AnalysisEventListener<ExcelPropertyIndexModel>() {
@Override
public void invoke(ExcelPropertyIndexModel object, AnalysisContext context) {
System.err.println("Row:" + context.getCurrentRowNum() + " Data:" + object);
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
System.err.println("doAfterAllAnalysed...");
}
};
ExcelReader excelReader = ExcelReaderFactory.getExcelReader(in, null, listener);
// 第二个参数为表头行数,按照实际设置
excelReader.read(new Sheet(1, 1, ExcelPropertyIndexModel.class));
}
}
public static class ExcelPropertyIndexModel extends BaseRowModel {
@ExcelProperty(value = "姓名", index = 0)
private String name;
@ExcelProperty(value = "年龄", index = 1)
private String age;
@ExcelProperty(value = "邮箱", index = 2)
private String email;
@ExcelProperty(value = "地址", index = 3)
private String address;
@ExcelProperty(value = "性别", index = 4)
private String sax;
@ExcelProperty(value = "高度", index = 5)
private String heigh;
@ExcelProperty(value = "备注", index = 6)
private String last;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getSax() {
return sax;
}
public void setSax(String sax) {
this.sax = sax;
}
public String getHeigh() {
return heigh;
}
public void setHeigh(String heigh) {
this.heigh = heigh;
}
public String getLast() {
return last;
}
public void setLast(String last) {
this.last = last;
}
@Override
public String toString() {
return "ExcelPropertyIndexModel [name=" + name + ", age=" + age + ", email=" + email + ", address=" + address
+ ", sax=" + sax + ", heigh=" + heigh + ", last=" + last + "]";
}
}
}
以上就是关于easyexcel的使用方法介绍,如有疑问,欢迎交流指正。