POI & easyExcel

  • 概念介绍
  • POI 操作
    • 1) 写
    • 2) 读
  • EasyExcel
    • 1) 写
    • 2)读

感谢狂神的分享:B站视频地址

概念介绍

POI

Apache POI 官网:http://poi.apache.org

百度百科介绍:


easyExcel

easyExcel github:https://github.com/alibaba/easyexcel

easyExcel API:https://easyexcel.opensource.alibaba.com/


POI 与 easyExcel 在解析Excel时的对比:

POI 操作

新建一个maven项目,导入以下依赖

<dependencies><!-- excel 03 --><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>5.2.3</version></dependency><!-- excel 07 --><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>5.2.3</version></dependency><!-- 日期格式化工具 --><dependency><groupId>joda-time</groupId><artifactId>joda-time</artifactId><version>2.12.1</version></dependency><!-- 单元测试工具 --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope></dependency>
</dependencies>

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

1、03版本和07版本存在兼容性问题,03版本最多只能有65535行,07版本没有限制
2、03版本的文件后缀是xls,07版本的后缀是xlsx
3、pom文件中对应的引用包类型不用
4、java代码中引用的对象不同
5、logo不同


WorkBook 有下面几个实现类:

1) 写

HSSFWorkbook: 03版工作簿
XSSFWorkbook: 07版工作簿
【对象的区别、文件的后缀!!!】

数据单个写入:

public class ReadTest {//构建路径String path="D:\\IdeaProjects\\excel_studay\\";@Testpublic void testWrite03() throws Exception {//创建新的工作簿HSSFWorkbook workbook = new HSSFWorkbook();// 在Excel工作簿中建一张表//Sheet sheet = workbook.createSheet();// 重载:指定 sheet 页的名字Sheet sheet = workbook.createSheet("狂神观众统计表");//创建行(row1)Row row1 = sheet.createRow(0);//创建单元格(col1-1)Cell cell11 = row1.createCell(0);cell11.setCellValue("今日新增观众");//创建单元格(col1-2)Cell cell12 = row1.createCell(1);cell12.setCellValue(999);//创建行(row2)Row row2 = sheet.createRow(1);//创建单元格(col2-1)Cell cell21 = row2.createCell(0);cell21.setCellValue("统计时间");//创建单元格(col2-2)Cell cell22 = row2.createCell(1);String dateTime = new DateTime().toString("yyyy-MM-dd HH:mm:ss");cell22.setCellValue(dateTime);//新建一个输出文件流(注意先创建文件夹)FileOutputStream out = new FileOutputStream(path + "狂神观众统计表03.xls");//把相应的Excel工作簿存盘workbook.write(out);//操作结束,关闭文件out.close();System.out.println("文件生成成功");}@Testpublic void testWrite07() throws Exception{//创建新的工作簿,只有对象发生了变化XSSFWorkbook workbook = new XSSFWorkbook();// 如要新建一名为"会员登录统计"的工作表,其语句为:Sheet sheet =workbook.createSheet("狂神观众统计表");//创建行(row1)Row row1 = sheet.createRow(0);//创建单元格(col1-1)Cell cell11 = row1.createCell(0);cell11.setCellValue("今日新增观众");//创建单元格(col1-2)Cell cell12 = row1.createCell(1);cell12.setCellValue(999);//创建行(row2)Row row2 = sheet.createRow(1);//创建单元格(col2-1)Cell cell21 = row2.createCell(0);cell21.setCellValue("统计时间");//创建单元格(col2-2)Cell cell22 = row2.createCell(1);String dateTime = new DateTime().toString("yyyy-MM-dd HH:mm:ss");cell22.setCellValue(dateTime);//新建一个输出文件流(注意先创建文件夹)FileOutputStream out = new FileOutputStream(path + "狂神观众统计表07.xlsx");//把相应的Excel工作簿存盘workbook.write(out);//操作结束,关闭文件out.close();System.out.println("文件生成成功");}
}

数据批量写入

  • HSSF(03版)

    • 优点:过程中写入缓存,不操作磁盘,最后一次性写入磁盘,速度快
    • 缺点:最多只能处理 65536 行,否则会抛出异常:
ava.lang.IllegalArgumentException: Invalid row number (65536) outside allowable range (0..65535)
//65536行数据,只需要1.176
@Test
public void write03BigData() throws IOException {long begin = System.currentTimeMillis();//创建簿Workbook workbook = new HSSFWorkbook();//创建表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("over");FileOutputStream fileOutputStream = new FileOutputStream(path + "TestWrite03BigData.xls");workbook.write(fileOutputStream);fileOutputStream.close();long end = System.currentTimeMillis();System.out.println((double) (end-begin)/1000);
}
  • XSSF(07版)

    • 缺点:写数据时速度非常慢,非常耗内存,也会发生内存溢出,如100万条
    • 优点:可以写较大的数据量,如20万条
/*
同样都是65536行数据,07版耗时约为 03版的六七倍
65536行数据,需要7.522s
*/
@Test
public void testWrite07BigData() throws Exception {// 时间long begin = System.currentTimeMillis();// 创建一个文件簿Workbook workbook = new XSSFWorkbook();// 创建表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("over");// 输出文件FileOutputStream outputStream = new FileOutputStream(path + "testWrite07BigData.xlsx");workbook.write(outputStream);outputStream.close();long end = System.currentTimeMillis();System.out.println((double) (end-begin)/1000);
}
  • SXSSF(升级版)

    • 优点:可以写非常大的数据量,如100万条甚至更多条,写数据速度快,占用更少的内存
    • 注意:
      1)过程中会产生临时文件,需要清理临时文件
      2)默认由100条记录被保存在内存中,如果超过这数量,则最前面的数据被写入临时文件
      3)如果想自定义内存中数据的数量,可以使用new SXSSFWorkbook(数量)
// 10W 条数据,只需要2.158s
@Test
public void testWrite07BigDataS() 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("over");// 输出文件FileOutputStream outputStream = new FileOutputStream(PATH + "testWrite07BigDataS.xlsx");workbook.write(outputStream);outputStream.close();// 清除临时文件!((SXSSFWorkbook) workbook).dispose();long end = System.currentTimeMillis();System.out.println((double) (end-begin)/1000);
}
  • SXSSFWorkbook的官方解释:实现“BigGridDemo”策略的流式XSSFWorkbook版本。这允许写入非常大的文件而不会耗尽内存,因为任何时候只有可配置的行部分被保存在内存中。

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

OOM问题,使用 Jprofile 定位。

2) 读

HSSFWorkbook(03版)

@Test
public void testRead03() throws Exception {// 获取文件流FileInputStream inputStream = new FileInputStream(PATH + "狂神观众统计表03.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(1);// 读取值的时候,一定要注意类型!System.out.println(cell.getNumericCellValue());inputStream.close();
}

XSSFWorkbook(07版)

@Test
public void testRead07() throws Exception {// 获取文件流FileInputStream inputStream = new FileInputStream(PATH + "狂神观众统计表07.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(1);// 读取值的时候,一定要注意类型!System.out.println(cell.getNumericCellValue());inputStream.close();
}

读取不同数据类型

@Test
public void testTypeCell() throws Exception{//获取文件流InputStream inputStream = new FileInputStream(PATH+"测试读取文件.xlsx");//创建一个工作簿,使用 excel能操作的这边都可以操作Workbook workbook = new XSSFWorkbook(inputStream);//得到表Sheet sheet = workbook.getSheetAt(0);//读取标题内容Row rowTitle = sheet.getRow(0);// 转换科学计数法DecimalFormat df = new DecimalFormat("##");if (rowTitle!=null){//读取列,得到一行有多少列有数据int cellCount = rowTitle.getPhysicalNumberOfCells();for (int cellNum = 0; cellNum < cellCount; cellNum++) {Cell cell = rowTitle.getCell(cellNum);if (cell!=null){String cellValue = cell.getStringCellValue();System.out.print(cellValue+"|");}}System.out.println();}//获取表中的内容,从第2行开始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++) {Cell cell = rowData.getCell(cellNum);if (cell!=null){//判断单元格类型CellType cellType = cell.getCellType();String cellValue="";switch (cellType){case STRING://字符串cellValue=String.valueOf(cell.getStringCellValue());break;case BOOLEAN://布尔cellValue = String.valueOf(cell.getBooleanCellValue());break;case BLANK://空break;case NUMERIC://数字(日期、普通数字)if("General".equals(cell.getCellStyle().getDataFormatString())){    //普通double类型cellValue = Double.toString(cell.getNumericCellValue());}else if("m/d/yy".equals(cell.getCellStyle().getDataFormatString())){cellValue = new DateTime(cell.getDateCellValue()).toString("yyyy-MM-dd");}else{  //科学计数法cellValue = df.format(cell.getNumericCellValue());}break;case ERROR:System.out.print("【数据类型错误】");break;default:throw new IllegalStateException("Unexpected value: " + cellType);}System.out.print(cellValue + "/t");}}}}inputStream.close();
}

公式

@Test
public void testFormula() throws Exception{InputStream is = new FileInputStream(PATH + "测试读取文件.xlsx");Workbook workbook = new XSSFWorkbook(is);Sheet sheet = workbook.getSheetAt(1);// 行和列都是从0计数:读取第4行第1列Row row = sheet.getRow(3);Cell cell = row.getCell(0);//公式计算器FormulaEvaluator formulaEvaluator = new XSSFFormulaEvaluator((XSSFWorkbook) workbook);// 输出单元内容CellType cellType = cell.getCellType();switch (cellType) {case FORMULA:   //如果是公式,进行下面操作//得到公式String formula = cell.getCellFormula();System.out.println(formula);        // 输出: SUM(A1:A3)CellValue evaluate = formulaEvaluator.evaluate(cell);String cellValue = evaluate.formatAsString();System.out.println(cellValue);      // 输出: 600.0break;}is.close();
}

EasyExcel

1) 写

  • DemoData: 实体类
@Getter
@Setter
@EqualsAndHashCode
public class DemoData {@ExcelProperty("字符串标题")private String string;@ExcelProperty("日期标题")private Date date;@ExcelProperty("数字标题")private Double doubleData;@ExcelIgnoreprivate String ignore;
}
  • 测试类
public class EasyExcelTest {//构建路径String PATH="D:\\IdeaProjects\\excel_studay\\";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;}//注意 simpleWrite在数据量不大的情况下可以使用(5000以内,具体也要看实际情况),数据量大参照 重复多次写入@Testpublic void simpleWrite() {// 写法1 JDK8+// since: 3.0.0-beta1String fileName = PATH + "easyExcelWrite.xlsx";/* 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭如果这里想使用03 则 传入excelType参数即可*/EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(() -> {// 分页查询数据return data();});// 写法2EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());// 写法3try (ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build()) {WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();excelWriter.write(data(), writeSheet);}}
}

2)读

持久层 DemoDAO

/*** 假设这个是你的DAO存储。当然还要这个类让spring管理,当然你不用需要存储,也不需要这个类。**/
public class DemoDAO {public void save(List<DemoData> list) {// 如果是mybatis,尽量别直接调用多次insert,自己写一个mapper里面新增一个方法batchInsert,所有数据一次性插入}
}
  • 读写监听类 DemoDataListener
@Slf4j
public class DemoDataListener implements ReadListener<DemoData> {//每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收private static final int BATCH_COUNT = 100;//缓存的数据private List<DemoData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);private DemoDAO demoDAO;public DemoDataListener() {demoDAO = new DemoDAO();}public DemoDataListener(DemoDAO demoDAO) {this.demoDAO = demoDAO;}//这个每一条数据解析都会来调用@Overridepublic void invoke(DemoData data, AnalysisContext context) {log.info("解析到一条数据:{}", JSON.toJSONString(data));cachedDataList.add(data);// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOMif (cachedDataList.size() >= BATCH_COUNT) {saveData();// 存储完成清理 listcachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);}}//所有数据解析完成了 都会来调用@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {// 这里也要保存数据,确保最后遗留的数据也存储到数据库saveData();log.info("所有数据解析完成!");}//加上存储数据库private void saveData() {log.info("{}条数据,开始存储数据库!", cachedDataList.size());demoDAO.save(cachedDataList);log.info("存储数据库成功!");}
}
  • 测试方法
/*** 最简单的读* 1. 创建excel对应的实体对象 参照{@link DemoData}* 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener}* 3. 直接读即可*/
@Test
public void simpleRead() {// 写法1:JDK8+ ,不用额外写一个DemoDataListener// since: 3.0.0-beta1String fileName = PATH + "easyExcelWrite.xlsx";// 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭// 这里每次会读取100条数据 然后返回过来 直接调用使用数据就行EasyExcel.read(fileName, DemoData.class, new PageReadListener<DemoData>(dataList -> {for (DemoData demoData : dataList) {System.out.println("读取到一条数据{}"+ JSON.toJSONString(demoData));;}})).sheet().doRead();// 写法2:// 匿名内部类 不用额外写一个DemoDataListener// 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭EasyExcel.read(fileName, DemoData.class, new ReadListener<DemoData>() {//单次缓存的数据量public static final int BATCH_COUNT = 100;//临时存储private List<DemoData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);@Overridepublic void invoke(DemoData data, AnalysisContext context) {cachedDataList.add(data);if (cachedDataList.size() >= BATCH_COUNT) {saveData();// 存储完成清理 listcachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);}}@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {saveData();}//加上存储数据库private void saveData() {System.out.println("{}条数据,开始存储数据库!"+ cachedDataList.size());System.out.println("存储数据库成功!");}}).sheet().doRead();// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去// 写法3:// 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();// 写法4// 一个文件一个readertry (ExcelReader excelReader = EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).build()) {// 构建一个sheet 这里可以指定名字或者noReadSheet readSheet = EasyExcel.readSheet(0).build();// 读取一个sheetexcelReader.read(readSheet);}
}

文档地址:关于Easyexcel

POIExcel--狂神相关推荐

  1. 狂神Spring Boot 员工管理系统 超详细完整实现教程(小白轻松上手~)

    [SpringBoot-web系列]前文: SpringBoot-web开发(一): 静态资源的导入(源码分析) SpringBoot-web开发(二): 页面和图标定制(源码分析) SpringBo ...

  2. 文件上传(JavaWeb 狂神笔记)

    跟着狂神的代码看一天了,泪目,我终于成功了!特此记录~ 我的环境:IDEA 2020,Tomcat 9.0.24,Maven 3.8.1 (环境其实要求应该没那么严,我跟狂神的也不完全一样~) 视频链 ...

  3. 支付宝支付 第十二集:狂神、飞哥支付宝支付配置代码(免费资源,拿走不谢)

    支付宝支付 第十二集:狂神.飞哥支付宝支付配置代码(免费资源,拿走不谢) 一.资源 链接:https://pan.baidu.com/s/1S-VAAMxiaPkgb2XZMQYEjA 提取码:091 ...

  4. java mybatis狂神说sql_狂神说SpringBoot09:整合MyBatis

    狂神说SpringBoot系列连载课程,通俗易懂,基于SpringBoot2.2.5版本,欢迎各位狂粉转发关注学习.未经作者授权,禁止转载 整合MyBatis 官方文档:http://mybatis. ...

  5. mysql 2006测试_狂神说MySQL06:事务和索引

    狂神说MySQL系列连载课程,通俗易懂,基于MySQL5.7.19版本,欢迎各位狂粉转发关注学习.禁止随意转载,转载记住贴出B站视频链接及公众号链接! 上课视频同步文档 事务和索引 事务 什么是事务 ...

  6. Java入门学习笔记[狂神说Java]

    写在前面: 本文根据B站狂神说Java 与菜鸟教程 整理而来,仅供个人学习使用,如有侵权,请联系删除. 文章目录 IDEA使用 Java基础01:注释 Java基础02:数据类型 Java基础03:类 ...

  7. 狂神java什么来头_狂神说SpringBoot18:集成SpringSecurity

    狂神说SpringBoot系列连载课程,通俗易懂,基于SpringBoot2.2.5版本,欢迎各位狂粉转发关注学习.未经作者授权,禁止转载 SpringSecurity 安全简介 在 Web 开发中, ...

  8. 狂神说spring笔记

    B站 https://www.bilibili.com/video/BV1WE411d7Dv 狂神说Spring01:概述及IOC理论推导 https://mp.weixin.qq.com/s/VM6 ...

  9. spring mvc是什么_狂神说SpringMVC01:什么是SpringMVC

    狂神说SpringMVC系列连载课程,通俗易懂,基于Spring5版本(视频同步),欢迎各位狂粉转发关注学习.未经作者授权,禁止转载 1.回顾MVC 1.1.什么是MVC MVC是模型(Model). ...

  10. 【狂神说】Redis笔记

    文章目录 1.Nosql概述 1.1 为什么要用Nosql 1.2 什么是NoSQL 1.3 阿里巴巴演进分析 2.NoSQL的四大分类 3.Redis入门 3.1 概述 3.2 Windows安装 ...

最新文章

  1. win10突然只剩下c盘和d盘了_电脑C盘爆满飘红?系统卡?试试这两种解决办法
  2. C++类的定义和声明
  3. python简单网络爬虫_【Python】简单的网络爬虫
  4. 缓存之 ACache
  5. chart.js 饼图显示百分比_Excel制作华夫饼图,其实很简单
  6. 框架Thinkphp5 简单的实现行为 钩子 Hook
  7. android 删除开机动画,Android开机logo和开机动画的修改
  8. java 时间格式化 注解_Java关于时间格式化的方法
  9. 我的框架-Unity3d中的用户数据储存模块UserDB
  10. opencv 将视频流转换成帧图像(支持asf,mp4,avi)
  11. Oracle实现竖表转横表的几种常用方法(行转列)
  12. 双臂UR5的Gazebo配置
  13. kernel 选项详解(stlinux2.3)
  14. 回归算法(最小二乘法拟合)
  15. 网络舆情总结汇报报告如何撰写的方法技巧
  16. Vue+Element-UI 上传图片,打开相机,相册
  17. 在Windows中安装MinGW-w64最新版本(目前12.1.0)
  18. 2021年软考信息系统监理师考试知识点整理
  19. 36.(cesium篇)cesium站立的圆面
  20. Gluon新机器学习库,学习库中的富二代丨又拖了后腿,9亿4G用户平均月流量2007M【软件网每日新闻播报│第10-23期】

热门文章

  1. Java基础公元纪年法换算天干地支纪年法
  2. 【AGC】SDK未经用户同意获取AndroidID问题
  3. 【Redis高频面试题系列】:说说Redis的rehash过程
  4. AFDX(ARINC664)的网络协议——MAC层
  5. 小练手:用Canvas绘制谢尔宾斯基三角形
  6. [网络安全学习篇10]:扫描技术、暴力破解工具(千峰网络安全视频笔记 10 day)
  7. 等离子电视工作原理(转)
  8. 携程CPS分佣怎么推广?
  9. 军队文职(数学2+物理)——高等数学 5、导数
  10. amazeui学习笔记--css(常用组件10)--导航条Topbar