赞
踩
POI
POI和easyExcel对比
版本差别
xls-03版 一共有65536行,xlsx-07版 则没有限制。
项目包结构
工作簿
03版本 HSSFWorkbook,07版本 XSSFWorkbook
代码
pom.xml
<!--导入依额--> <dependencies> <!--xls(03)--> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.9</version> </dependency> <!--xlsx(07)--> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.9</version> </dependency> <!--日期格式化工具--> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> <version>2.10.1</version> </dependency> <!--test--> <dependency> <groupId>junit</groupId> <artifactId> junit</artifactId> <version>4.12</version> </dependency> </dependencies>
ExcelWriteTest.java
package com.lm; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Cell; 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; import org.joda.time.DateTime; import org.junit.Test; import java.io.FileOutputStream; public class ExcelWriteTest { //存储路径 String PATH = "C:/Users/Lenovo/Desktop/POI/"; @Test public void testExcel03() throws Exception { //1.创建工作簿 Workbook workbook = new HSSFWorkbook(); //2.创建工作表 Sheet sheet = workbook.createSheet("工作表一"); //3.创建行 Row row_1 = sheet.createRow(0); //第一行 //4.创建单元格 Cell cell_11 = row_1.createCell(0); //(1,1) cell_11.setCellValue("姓名"); // 输入数据 Cell cell_12 = row_1.createCell(1); //(1,2) cell_12.setCellValue("性别"); Cell cell_13 = row_1.createCell(2); //(1,3) cell_13.setCellValue("填表日期"); Row row_2 = sheet.createRow(1); //第二行 Cell cell_21 = row_2.createCell(0); //(2,1) cell_21.setCellValue("李白"); Cell cell_22 = row_2.createCell(1); //(2,2) cell_22.setCellValue("男"); Cell cell_23 = row_2.createCell(2); //(2,3) String time = new DateTime().toString("yyyy-MM-dd HH:mm:ss"); cell_23.setCellValue(time); //生成一张excel表(IO 流)03版本.xls FileOutputStream fileOutputStream = new FileOutputStream(PATH + "Excel03.xls"); workbook.write(fileOutputStream); //输出 fileOutputStream.close(); //关闭流 System.out.println("excel03生成成功!"); } @Test public void testExcel07() throws Exception { //1.创建工作簿 Workbook workbook = new XSSFWorkbook(); //2.创建工作表 Sheet sheet = workbook.createSheet("工作表一"); //3.创建行 Row row_1 = sheet.createRow(0); //第一行 //4.创建单元格 Cell cell_11 = row_1.createCell(0); //(1,1) cell_11.setCellValue("姓名"); // 输入数据 Cell cell_12 = row_1.createCell(1); //(1,2) cell_12.setCellValue("性别"); Cell cell_13 = row_1.createCell(2); //(1,3) cell_13.setCellValue("填表日期"); Row row_2 = sheet.createRow(1); //第二行 Cell cell_21 = row_2.createCell(0); //(2,1) cell_21.setCellValue("李白"); Cell cell_22 = row_2.createCell(1); //(2,2) cell_22.setCellValue("男"); Cell cell_23 = row_2.createCell(2); //(2,3) String time = new DateTime().toString("yyyy-MM-dd HH:mm:ss"); cell_23.setCellValue(time); //生成一张excel表(IO 流)07版本.xlsx FileOutputStream fileOutputStream = new FileOutputStream(PATH + "Excel07.xlsx"); workbook.write(fileOutputStream); //输出 fileOutputStream.close(); //关闭流 System.out.println("excel07生成成功!"); } }
数据批量导入
大文件写 HSSF 03版本
缺点:最多只能处理65536行,否则回抛异常
java.lang.IllegalArgumentException: Invalid row number (65536) outside allowable range (0..65535)
优点:过程中写入缓存,不操作磁盘,最后一次性写入磁盘,速度快
ExcelWriteTest.java
@Test public void testWrite03BigData() throws Exception { //时间 long begin = System.currentTimeMillis(); //创建簿 Workbook workbook = new HSSFWorkbook(); //创建表 Sheet sheet = workbook.createSheet(); //写入数据 for (int rowNum = 0; rowNum < 65536; rowNum++){ Row row = sheet.createRow(rowNum); for (int cellNum = 0; cellNum <10; cellNum++){ Cell cell = row.createCell(cellNum); cell.setCellValue(cellNum); } } System.out.println("write over"); //输出流 FileOutputStream fileOutputStream = new FileOutputStream( PATH + "testBigData03.xls"); workbook.write(fileOutputStream); fileOutputStream.close(); //关闭流 long end = System.currentTimeMillis(); System.out.println((double)(end-begin)/1000); }
大文件写XSSF
缺点:写数据时速度非常慢,非常耗内存,会发生内存溢出,如100万条数据时
优点:可以写较大的数据,如20万条数据
ExcelWriteTest.java
@Test public void testWrite07BigData() throws Exception { //时间 long begin = System.currentTimeMillis(); //创建簿 Workbook workbook = new XSSFWorkbook(); //创建表 Sheet sheet = workbook.createSheet(); //写入数据 for (int rowNum = 0; rowNum < 65537; rowNum++){ Row row = sheet.createRow(rowNum); for (int cellNum = 0; cellNum <10; cellNum++){ Cell cell = row.createCell(cellNum); cell.setCellValue(cellNum); } } System.out.println("write over"); //输出流 FileOutputStream fileOutputStream = new FileOutputStream( PATH + "testBigData07.xlsx"); workbook.write(fileOutputStream); fileOutputStream.close(); //关闭流 long end = System.currentTimeMillis(); System.out.println((double)(end-begin)/1000); }
大文件写SXSSF
优点:可以写非常大的数据量,如100万条甚至更多,写数据速度快,占用内存更少
注意:
过程会产生临时文件,需要清理临时文件
默认为100条记录被保存在内存中,如果超过超过这个数量,则最前面的数据写入临时文件
如果想自定义内存中的数量,可以使用new SXSSFWorkbook(数量)
ExcelWriteTest.java
@Test public void testSupperWrite07BigData() throws Exception { //时间 long begin = System.currentTimeMillis(); //创建簿 Workbook workbook = new SXSSFWorkbook(); //创建表 Sheet sheet = workbook.createSheet(); //写入数据 for (int rowNum = 0; rowNum < 100000; rowNum++){ Row row = sheet.createRow(rowNum); for (int cellNum = 0; cellNum <10; cellNum++){ Cell cell = row.createCell(cellNum); cell.setCellValue(cellNum); } } System.out.println("write over"); //输出流 FileOutputStream fileOutputStream = new FileOutputStream( PATH + "testSuperData07.xlsx"); workbook.write(fileOutputStream);//写入 fileOutputStream.close(); //关闭流 ((SXSSFWorkbook) workbook).dispose();//清除临时文件 long end = System.currentTimeMillis(); System.out.println((double)(end-begin)/1000); }
03版本
ExcelReadTest.java
package com.lm; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.junit.Test; import java.io.FileInputStream; public class ExcelReadTest { //存储路径 String PATH = "C:/Users/Lenovo/Desktop/POI/"; @Test public void testRead03() throws Exception { //获取文件流 FileInputStream inputStream = new FileInputStream( PATH + "Excel03.xls" ); //1.获取工作簿,Excel里面的功能都能使用 Workbook workbook = new HSSFWorkbook(inputStream); //2.获得表,通过下标获取 Sheet sheet = workbook.getSheetAt(0); //3.获得行 Row row = sheet.getRow(0); //4.获得列 Cell cell = row.getCell(0); //getStringCellValue获取字符串类型的内容 System.out.println(cell.getStringCellValue()); //getNumericCellValue获取数字类型的内容 // System.out.println(cell.getNumericCellValue()); inputStream.close(); } }
07版本
ExcelReadTest.java
@Test public void testRead07() throws Exception { //获取文件流 FileInputStream inputStream = new FileInputStream( PATH + "Excel07.xlsx" ); //1.获取工作簿,Excel里面的功能都能使用 Workbook workbook = new XSSFWorkbook(inputStream); //2.获得表,通过下标获取 Sheet sheet = workbook.getSheetAt(0); //3.获得行 Row row = sheet.getRow(0); //4.获得列 Cell cell = row.getCell(0); //getStringCellValue获取字符串类型的内容 System.out.println(cell.getStringCellValue()); //getNumericCellValue获取数字类型的内容 // System.out.println(cell.getNumericCellValue()); inputStream.close(); }
注:获取值的类型需要注意
读取不同数据类型 (重要)
ExcelReadTest.java
@Test public void testCellType() throws Exception { //获取文件流 FileInputStream inputStream = new FileInputStream( PATH + "明细表.xlsx" ); //创建工作簿 Workbook workbook = new XSSFWorkbook(inputStream); Sheet sheet = workbook.getSheetAt(0); //获取标题内容 Row rowTitle = sheet.getRow(0); if (rowTitle != null){ int cellCount = rowTitle.getPhysicalNumberOfCells(); for (int cellNum = 0; cellNum < cellCount; cellNum++ ){ Cell cell = rowTitle.getCell(cellNum); if (cell != null){ int cellType = cell.getCellType(); String cellValue = cell.getStringCellValue(); System.out.print(cellValue + " | "); } } System.out.println(); } //获取表中的内容 int rowCount = sheet.getPhysicalNumberOfRows(); for (int rowNum = 1; rowNum < rowCount; rowNum++) { Row rowData = sheet.getRow(rowNum); if (rowData != null) { //读取列 int cellCount = rowTitle.getPhysicalNumberOfCells(); for (int cellNum = 0; cellNum < cellCount; cellNum++) { System.out.print("[" + (rowNum + 1) + "-" + (cellNum + 1) + "]"); Cell cell = rowData.getCell(cellNum); //匹配列的数据类型 if (cell != null) { int cellType = cell.getCellType(); String cellValue = ""; switch (cellType) { case HSSFCell.CELL_TYPE_STRING: //String System.out.print("[String]"); cellValue = cell.getStringCellValue(); break; case HSSFCell.CELL_TYPE_BOOLEAN: //Boolean System.out.print("[Boolean]"); cellValue = String.valueOf(cell.getBooleanCellValue()); break; case HSSFCell.CELL_TYPE_BLANK: //空 System.out.print("[Blank]"); break; case HSSFCell.CELL_TYPE_NUMERIC: //数字(日期、普通数字) System.out.print("[Numeric]"); if (HSSFDateUtil.isCellDateFormatted(cell)) { //日期 System.out.print("[日期]"); Date date = cell.getDateCellValue(); cellValue = new DateTime(date).toString("yyyy-MM-dd"); }else{ //不是日期格式,防止数字过长 System.out.print("[转换为String输出]"); cell.setCellType(HSSFCell.CELL_TYPE_STRING); cellValue = cell.toString(); } break; case HSSFCell.CELL_TYPE_ERROR: //Error System.out.print("[数据类型错误]"); break; } System.out.println(cellValue); } } } } inputStream.close(); }
计算公式(了解)
ExcelReadTest.java
@Test public void testFormula() throws Exception { FileInputStream inputStream = new FileInputStream( PATH + "公式.xlsx" ); Workbook workbook = new XSSFWorkbook(inputStream); Sheet sheet = workbook.getSheetAt(0); Row row = sheet.getRow(4); Cell cell = row.getCell(0); //获取计算公式 FormulaEvaluator formulaEvaluator = new XSSFFormulaEvaluator((XSSFWorkbook)workbook); //输出单元格的内容 int cellType = cell.getCellType(); switch (cellType){ case Cell.CELL_TYPE_FORMULA: //公式 String formula = cell.getCellFormula(); System.out.println(formula); //计算 CellValue evaluate = formulaEvaluator.evaluate(cell); String cellValue = evaluate.formatAsString(); System.out.println(cellValue); break; } }
公式.xlsx
参考文档 https://www.yuque.com/easyexcel/doc/easyexcel
pom.xml
<!-- easyexcel --> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.2.6</version> </dependency> <!-- lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.12</version> </dependency> <!-- fastjson --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.62</version> </dependency>
注:导入easyexcel依赖就不用导xls(03)、xlsx(07),否则会冲突
easyExcel 写
DemoData.java
package com.lm.easy; import com.alibaba.excel.annotation.ExcelIgnore; import com.alibaba.excel.annotation.ExcelProperty; import lombok.Data; import java.util.Date; @Data public class DemoData { @ExcelProperty("字符串标题") private String string; @ExcelProperty("日期标题") private Date date; @ExcelProperty("数字标题") private Double doubleData; /** * 忽略这个字段 */ @ExcelIgnore private String ignore; }
EasyTest.java
package com.lm.easy; import com.alibaba.excel.EasyExcel; import org.junit.Test; import java.util.ArrayList; import java.util.Date; import java.util.List; public class EasyTest { private List<DemoData> data() { List<DemoData> list = new ArrayList<DemoData>(); for (int i = 0; i < 10; i++) { DemoData data = new DemoData(); data.setString("字符串" + i); data.setDate(new Date()); data.setDoubleData(0.56); list.add(data); } return list; } //根据list 写入excel @Test public void simpleWrite() { //存储路径 String PATH = "C:/Users/Lenovo/Desktop/POI/"; String fileName = PATH + "EasyExcel.xlsx"; // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 // 如果这里想使用03 则 传入excelType参数即可 //参数:write(fileName,格式类) //sheet(表名) //doWrite(数据) EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data()); } }
EasyExcel.xlsx
easyExcel 读
DemoDataListener.java
package com.lm.easy; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.fastjson.JSON; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; // 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去 public class DemoDataListener extends AnalysisEventListener<DemoData> { private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class); /** * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收 */ private static final int BATCH_COUNT = 5; List<DemoData> list = new ArrayList<DemoData>(); /** * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。 */ private DemoDAO demoDAO; public DemoDataListener() { // 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数 demoDAO = new DemoDAO(); } /** * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来 * * @param demoDAO */ public DemoDataListener(DemoDAO demoDAO) { this.demoDAO = demoDAO; } /** * 这个每一条数据解析都会来调用 * * @param data * one row value. Is is same as {@link AnalysisContext#readRowHolder()} * @param context */ @Override public void invoke(DemoData data, AnalysisContext context) { System.out.println(JSON.toJSONString(data)); //控制台输出 list.add(data); // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM if (list.size() >= BATCH_COUNT) { saveData(); // 存储完成清理 list list.clear(); } } /** * 所有数据解析完成了 都会来调用 * * @param context */ @Override public void doAfterAllAnalysed(AnalysisContext context) { // 这里也要保存数据,确保最后遗留的数据也存储到数据库 saveData(); LOGGER.info("所有数据解析完成!"); } /** * 加上存储数据库 */ private void saveData() { LOGGER.info("{}条数据,开始存储数据库!", list.size()); demoDAO.save(list);//持久化 LOGGER.info("存储数据库成功!"); } }
DemoDao.java
package com.lm.easy;
import java.util.List;
/**
* 假设这个是你的DAO存储。当然还要这个类让spring管理,当然你不用需要存储,也不需要这个类。
**/
public class DemoDAO {
public void save(List<DemoData> list) {
// 如果是mybatis,尽量别直接调用多次insert,自己写一个mapper里面新增一个方法batchInsert,所有数据一次性插入
}
}
@Override 报错
Languag level 5 改为 8
EasyTest.java
/**
* 最简单的读
* <p>1. 创建excel对应的实体对象 参照{@link DemoData}
* <p>2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener}
* <p>3. 直接读即可
*/
@Test
public void simpleRead() {
// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
// 写法1:
String fileName = PATH + "EasyExcel.xlsx";
// 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();
}
Error:java: Compilation failed: internal java compiler error
version 5 改为 8
控制台输出
"C:\Program Files\Java\jdk1.8.0_131\bin\java.exe" ... SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. {"date":1598086056000,"doubleData":0.56,"string":"字符串0"} {"date":1598086056000,"doubleData":0.56,"string":"字符串1"} {"date":1598086056000,"doubleData":0.56,"string":"字符串2"} {"date":1598086056000,"doubleData":0.56,"string":"字符串3"} {"date":1598086056000,"doubleData":0.56,"string":"字符串4"} {"date":1598086056000,"doubleData":0.56,"string":"字符串5"} {"date":1598086056000,"doubleData":0.56,"string":"字符串6"} {"date":1598086056000,"doubleData":0.56,"string":"字符串7"} {"date":1598086056000,"doubleData":0.56,"string":"字符串8"} {"date":1598086056000,"doubleData":0.56,"string":"字符串9"} Process finished with exit code 0
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。