POI和easyExcle使用详解

阅读: 评论:0

POI和easyExcle使用详解

POI和easyExcle使用详解

文章目录

  • 1、Apache POI
    • 1.1、导入依赖
    • 1.2、03 | 07 版本
    • 1.3、大数据量的写入
      • 1.3.1、大文件写HSSF
      • 1.3.2、大文件写XSSF
      • 1.3.3、大文件写SXSSF
    • 1.4、POI-Excel读
      • 1.4.1、03|07 版本
      • 1.4.2、读取不同的数据类型(难点)
      • 1.4.3、计算公式
  • 2、EasyExcel
    • 2.1、EasyExcel操作
      • 2.1.1、导入依赖
      • 2.1.2、写入测试
      • 2.1.3、读取测试

常用信息

  1. 将用户信息导出为excel表格(出数据… )
  2. 将Excel表中的信息录入到网站数据库(习题上… )

开发中经常会设计到excel的处理,如导出Excel ,导入Excel到数据库中!
操作ExceI目前比较流行的就是Apache POI和阿里巴巴的easyExcel !

1、Apache POI

Apache POI官网: /

POI是Apache软件基金会的,POI为“Poor Obfuscation Implementation”的首字母缩写,意为“简洁版的模糊实现”。
所以POI的主要功能是可以用Java操作Microsoft Office的相关文件,这里我们主要讲Excel

1.1、导入依赖

        <!--xls--><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>3.17</version></dependency><!--xlsx--><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>3.17</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>

1.2、03 | 07 版本

03 | 07 版本的写,就是对象不同,方法一样

需要注意: 2003版本和2007版本存在兼容性的问题! 03最多只有65535行

03版本:

package com.chen;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.joda.time.DateTime;
import org.junit.Test;import java.io.FileNotFoundException;
import java.io.FileOutputStream;public class ExcelWriteTest {String PATH = "E:\Directory\假期\Poi-EasyExcel\chen-poi\";@Testpublic void  testWrite03() throws Exception {// 1、创建一个工作簿Workbook workbook = new HSSFWorkbook();// 2、创建一个工作表Sheet sheet = ateSheet("复联观众统计表");// 3、创建一个行 (1,1)Row row1 = ateRow(0);// 4、创建一个单元格Cell cell11 = ateCell(0);cell11.setCellValue("今日新增观众"); // 单元格:(1,1)Cell cell12 = ateCell(1);cell12.setCellValue(666); // 单元格:(1,2)// 第二行Row row2 = ateRow(1);Cell cell21 = ateCell(0);cell21.setCellValue("统计时间"); // 单元格:(2,1)Cell cell22 = ateCell(1);String time = new DateTime().toString("yyyy-MM-dd hh:mm:ss");cell22.setCellValue(time); // 单元格:(2,2)// 生成一张表(IO流) 03版本就是xls结尾!FileOutputStream fileOutputStream = new FileOutputStream(PATH + "复联观众统计表03.xls");workbook.write(fileOutputStream);// 关闭流fileOutputStream.close();System.out.println("生成完毕");} 
}

07版本:

package com.chen;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.FileNotFoundException;
import java.io.FileOutputStream;public class ExcelWriteTest {String PATH = "E:\Directory\假期\Poi-EasyExcel\chen-poi\";@Testpublic void  testWrite07() throws Exception {// 1、创建一个工作簿Workbook workbook = new XSSFWorkbook();// 2、创建一个工作表Sheet sheet = ateSheet("复联观众统计表");// 3、创建一个行 (1,1)Row row1 = ateRow(0);// 4、创建一个单元格Cell cell11 = ateCell(0);cell11.setCellValue("今日新增观众"); // 单元格:(1,1)Cell cell12 = ateCell(1);cell12.setCellValue(666); // 单元格:(1,2)// 第二行Row row2 = ateRow(1);Cell cell21 = ateCell(0);cell21.setCellValue("统计时间"); // 单元格:(2,1)Cell cell22 = ateCell(1);String time = new DateTime().toString("yyyy-MM-dd hh:mm:ss");cell22.setCellValue(time); // 单元格:(2,2)// 生成一张表(IO流) 07版本就是xlsx结尾!FileOutputStream fileOutputStream = new FileOutputStream(PATH + "复联观众统计表07.xlsx");workbook.write(fileOutputStream);// 关闭流fileOutputStream.close();System.out.println("生成完毕");} 
}


注意对象的一个区别,文件后缀!

1.3、大数据量的写入

1.3.1、大文件写HSSF

缺点:最多只能处理65536行,否则会抛出异常

java.lang.IllegalArgumentException: Invalid row number (65536) outside allowable range (0..65535)

优点:过程中写入缓存,不操作磁盘,最后一次性写入磁盘,速度快

@Test
public void testWrite03BidData() throws Exception {// 时间long begin = System.currentTimeMillis();// 创建一个簿Workbook workbook = new HSSFWorkbook();// 创建表Sheet sheet = ateSheet();// 写入数据for (int rowNum = 0; rowNum < 65536; rowNum++) {Row row = ateRow(rowNum);for (int cellNum = 0; cellNum < 10; cellNum++) {Cell cell = ateCell(cellNum);cell.setCellValue(cellNum);}}System.out.println("over");FileOutputStream outputStream = new FileOutputStream(PATH + "testWrite03BidData.xls");workbook.write(outputStream);outputStream.close();long end = System.currentTimeMillis();System.out.println((double)(end-begin)/1000);}

1.3.2、大文件写XSSF

缺点:写数据时速度非常慢,非常耗内存,也会发生内存溢出,如100万条

优点:可以写比较大的数据,如20万条

//耗时较长
@Test
public void testWrite07BidData() throws Exception {// 时间long begin = System.currentTimeMillis();// 创建一个簿Workbook workbook = new XSSFWorkbook();// 创建表Sheet sheet = ateSheet();// 写入数据for (int rowNum = 0; rowNum < 100000; rowNum++) {Row row = ateRow(rowNum);for (int cellNum = 0; cellNum < 10; cellNum++) {Cell cell = ateCell(cellNum);cell.setCellValue(cellNum);}}System.out.println("over");FileOutputStream outputStream = new FileOutputStream(PATH + "testWrite07BidData.xlsx");workbook.write(outputStream);outputStream.close();long end = System.currentTimeMillis();System.out.println((double)(end-begin)/1000);}

1.3.3、大文件写SXSSF

优点:可以写非常大的数据,如100万条甚至更多,写数据速度快,占用更少的内存

注意:

  • 过程中会产生临时文件,需要清理临时文件

  • 默认由100条记录被保存再内存中,如果超过这个数量,则最前面的数据被写入临时文件

  • 如果想自定义内存中数据的数量,可以使用new SXSSFWorkbook(数量)

@Test
public void testWrite07BidDataS() throws Exception {// 时间long begin = System.currentTimeMillis();// 创建一个簿Workbook workbook = new SXSSFWorkbook();// 创建表Sheet sheet = ateSheet();// 写入数据for (int rowNum = 0; rowNum < 100000; rowNum++) {Row row = ateRow(rowNum);for (int cellNum = 0; cellNum < 10; cellNum++) {Cell cell = ateCell(cellNum);cell.setCellValue(cellNum);}}System.out.println("over");FileOutputStream outputStream = new FileOutputStream(PATH + "testWrite07BidDataS.xlsx");workbook.write(outputStream);outputStream.close();// 清楚临时文件((SXSSFWorkbook) workbook).dispose();long end = System.currentTimeMillis();System.out.println((double)(end-begin)/1000);
}

SXSSFWorkbook-来至官方的解释:实现"BigGridDemo"策略的流式XSSFWorkbook版本。这允许写入非常大的文件而不会耗尽内存,因为任何时候只有可配置的行部分被保存在内存中。

请注意,仍然可能会消耗大量内存,这些内存基于您正在使用的功能,例如合并区域,注释…仍然只存储在内存中,因此如果广泛使用,可能需要大量内存。

1.4、POI-Excel读

1.4.1、03|07 版本

03版本

@Test
public void  testWrite03() throws Exception {// 1、获取文件流FileInputStream inputStream = new FileInputStream(PATH + "复联观众统计表03.xls");// 2、创建一个工作簿 使用Excel能操作的,他这里都能操作Workbook workbook = new HSSFWorkbook(inputStream);// 3、得到表Sheet sheet = SheetAt(0);// 4、得到行Row row = Row(0);// 5、得到列Cell cell = Cell(0);// 读取值得时候,一定需要注意类型// getStringCellValue 字符串类型System.out.StringCellValue());inputStream.close();
}

07版本

 @Testpublic void  testWrite07() throws Exception {// 1、获取文件流FileInputStream inputStream = new FileInputStream(PATH + "复联观众统计表07.xlsx");// 2、创建一个工作簿 使用Excel能操作的,他这里都能操作Workbook workbook = new XSSFWorkbook(inputStream);// 3、得到表Sheet sheet = SheetAt(0);// 4、得到行Row row = Row(0);// 5、得到列Cell cell = Cell(0);// 读取值得时候,一定需要注意类型// getStringCellValue 字符串类型System.out.StringCellValue());inputStream.close();}

1.4.2、读取不同的数据类型(难点)

    @Testpublic  void testCellType() throws IOException {// 1、获取文件流FileInputStream inputStream = new FileInputStream(PATH + "会员消费商品明细表.xls");// 2、创建一个工作簿 使用Excel能操作的,他这里都能操作Workbook workbook = new HSSFWorkbook(inputStream);Sheet sheet = SheetAt(0);// 3、获取标题内容Row rowTitle = Row(0);if(rowTitle != null){// 一点要掌握int cellCount = PhysicalNumberOfCells();for (int cellNum = 0; cellNum < cellCount; cellNum++) {Cell cell = Cell(cellNum);if (cell != null){CellType cellType = CellTypeEnum();String cellValue = StringCellValue();System.out.print(cellValue+" | ");}}System.out.println();}// 获取表中得内容int rowCount = PhysicalNumberOfRows();for (int rowNum = 0; rowNum < rowCount; rowNum++) {Row rowData = Row(rowNum);if (rowData != null){// 读取列int cellCount = PhysicalNumberOfCells();for (int cellNum = 0; cellNum < cellCount; cellNum++) {System.out.print("[" + (rowNum+1) + "-" + (cellNum) + "]");Cell cell = Cell(cellNum);//匹配列得数据类型if (cell!=null){CellType cellType = CellTypeEnum();String cellValue = "";switch (cellType){case STRING: // 字符串System.out.print("【字符串】");cellValue = StringCellValue();break;case BOOLEAN: // 布尔System.out.print("【BOOLEAN】");cellValue = String.BooleanCellValue());break;case BLANK: // 空System.out.print("【BLANK】");break;case _NONE:break;case NUMERIC: // 数字(日期、普通数字)System.out.print("【NUMERIC】");if(HSSFDateUtil.isCellDateFormatted(cell)){ //日期System.out.println("【日期】");Date date = DateCellValue();cellValue = new DateTime(date).toString("yyyy-MM-dd hh:mm:ss");}else {// 如果不是日期格式,防止数字过长!System.out.println("【普通数字转换为字符串输出】");cell.setCellType(CellType.STRING);cellValue = String();}break;case ERROR: // 布尔System.out.print("【数据类型错误】");break;case FORMULA:break;}System.out.println(cellValue);}}}}inputStream.close();}

1.4.3、计算公式

@Test
public void testFormula() throws IOException {FileInputStream inputStream = new FileInputStream(PATH+"计算公式.xls");HSSFWorkbook workbook = new HSSFWorkbook(inputStream);Sheet sheet = SheetAt(0);Row row = Row(4);Cell cell = Cell(0);// 拿到计算公式FormulaEvaluator formulaEvaluator = new HSSFFormulaEvaluator((HSSFWorkbook) workbook);// 输出单元格的内容CellType cellType = CellTypeEnum();switch (cellType){case FORMULA: // 公式String formula = CellFormula();System.out.println(formula);// 计算CellValue evaluate = formulaEvaluator.evaluate(cell);String cellValue = evaluate.formatAsString();System.out.println(cellValue);break;}
}

2、EasyExcel

easyExcel官网地址:

EasyExcel是阿里巴巴开源的一个excel处理框架 ,以使用简单、节省内存著称。
EasyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上-行行读取数据,逐个解析。
下图是EasyExcel和POI在解析Excel时的对比图。

官方文档:

2.1、EasyExcel操作

2.1.1、导入依赖

<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.2.6</version>
</dependency>

2.1.2、写入测试

  1. DemoData.java
@Data
public class DemoData {@ExcelProperty("字符串标题")private String string;@ExcelProperty("日期标题")private Date date;@ExcelProperty("数字标题")private Double doubleData;/**  忽略这个字段* */@ExcelIgnoreprivate String ignore;
}
  1. 测试写入数据
public class EasyTest {String PATH = "E:\Directory\假期\Poi-EasyExcel\chen-poi\";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;}@Testpublic void simpleWrite() {// 写法1String fileName =PATH+ "EasyTest.xlsx";// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭// write (fileName, 格式类)// sheet (表名)// doWrite (数据)EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());}
  1. 最终的结果:

2.1.3、读取测试

  1. DemoDataListener.java
package com.chen.east;import l.context.AnalysisContext;
import l.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 = Logger(DemoDataListener.class);private static final int BATCH_COUNT = 5;List<DemoData> list = new ArrayList<DemoData>();private DemoDAO demoDAO;public DemoDataListener() {// 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数demoDAO = new DemoDAO();}public DemoDataListener(DemoDAO demoDAO) {this.demoDAO = demoDAO;}// 读取数据会执行这个方法// DemoData 读取类型// AnalysisContext 分析上下文@Overridepublic void invoke(DemoData data, AnalysisContext context) {System.out.JSONString(data));LOGGER.info("解析到一条数据:{}", JSONString(data));list.add(data);// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOMif (list.size() >= BATCH_COUNT) {saveData(); // 持久化逻辑// 存储完成清理 listlist.clear();}}/*** 所有数据解析完成了 都会来调用** @param context*/@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {// 这里也要保存数据,确保最后遗留的数据也存储到数据库saveData();LOGGER.info("所有数据解析完成!");}/*** 加上存储数据库*/private void saveData() {LOGGER.info("{}条数据,开始存储数据库!", list.size());demoDAO.save(list);LOGGER.info("存储数据库成功!");}
}
  1. 测试读出数据
 @Testpublic void simpleRead() {// 写法1String fileName =PATH+ "EasyTest.xlsx";// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭// write (fileName, 格式类)// sheet (表名)// doWrite (数据)ad(fileName, DemoData.class,new DemoDataListener()).sheet("模板").doRead();}
  1. 数据库逻辑(自己实现)
package com.chen.east;import java.util.List;/*** 假设这个是你的DAO存储。当然还要这个类让spring管理,当然你不用需要存储,也不需要这个类。**/
public class DemoDAO {public void save(List<DemoData> list) {// 持久化操作// 如果是mybatis,尽量别直接调用多次insert,自己写一个mapper里面新增一个方法batchInsert,所有数据一次性插入}
}
  1. 测试结果:

学习视频链接:=7

本文发布于:2024-01-31 22:38:32,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170671191231892.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:详解   POI   easyExcle
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23