POI、Easy Excel操作Excel

文章目录

  • 1.常用的场景
  • 2.基本功能
  • 3.Excel在Java中是一个对象
  • 4. 简单的写(07版本(.xlsx)Excel)
    • 大文件写HSSF
    • 大文件写XSSF
    • 大文件写SXSSF
  • 5. Excel读
    • 5.1 读取遇到类型转化问题该怎么解决
    • 5.2 遇到Excel公式怎么办
  • 6. Easy Excel
    • 6.1简单的写
    • 6.2 简单的读

1.常用的场景

    1. 将用户信息导出为Excel表格(导出数据)
    1. 将Excel表中的信息录入到网站数据库中(习题上传)大大减轻网站录入量。开发中经常会用到设计处理Excel,如导入Excel和导出Excel
    1. 目前操作Excel比较流行的就是Apach的POI阿里巴巴的Easy Excel
    1. POI官网:https://poi.apache.org/
    1. Easy Excel官网:https://github.com/alibaba/easyexcel

2.基本功能

  • 1.POI的基本功能:(会比较麻烦,可能会出现OOM(Out Of Memory)异常)
    在这里插入图片描述
    其中:第一个HSSF和XSSF的区别(前者用03版本的Excel,后者用07年的Excel)
    • 1.1 内存问题:
      POI 当数据为100w的时候,先将100w的数据先加载到内存当中(OOM),再写入文件
    1. Easy Excel:
    • 2.1 简介,官方文档:(已经迁移到)https://easyexcel.opensource.alibaba.com/docs/current/
      在这里插入图片描述
    • 2.2 内存问题:
      相对于POI来说,上图反映了POI会把所有内容加载到内存当中,而Easy Excel会一行一行通过磁盘返回。

3.Excel在Java中是一个对象

在这里插入图片描述

    1. 工作簿
    1. 工作表

4. 简单的写(07版本(.xlsx)Excel)

03版本代码中有标注,生成文件时候,需要改后缀为:(.xls)

package com.dapeng;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.streaming.SXSSFWorkbook;
import org.joda.time.DateTime;
import org.junit.Test;import java.io.FileNotFoundException;
import java.io.FileOutputStream;/*** @Description* @Author zhaopeng* @Date 2023/10/13 9:49*/
public class ExcelWriteTest {@Testpublic void testWrite() throws Exception {String PATH = "D:\\ExcelTest\\";// 1.创建一个工作簿(SXSSF优化版的07的工作簿,HSSF是03年的)// Workbook workbook = new HSSFWorkbook();03版本Workbook workbook = new SXSSFWorkbook();// 2. 创建一个工作表Sheet sheet = workbook.createSheet("我的工作表");// 3. 创建一行(0代表从第一行开始创建)Row row1 = sheet.createRow(0);// 4. 创建一列(0代表从第一列开始创建),Cell代表一个单元格Cell cell11 = row1.createCell(0);Cell cell12 = row1.createCell(1);// 5. 给单元格赋值cell11.setCellValue("测试数据1-1");cell12.setCellValue("Cell12数据");// 来个第二行Row row2 = sheet.createRow(1);Cell cell21 = row2.createCell(0);Cell cell22 = row2.createCell(1);// 来个时间String time = new DateTime().toString("yyyy-MM-dd HH:mm:ss");cell21.setCellValue(time);cell22.setCellValue("第二行第二个数据");// 生成一张表FileOutputStream fileOutputStream = new FileOutputStream(PATH + "test.xlsx");workbook.write(fileOutputStream);fileOutputStream.close();}
}

效果:
在这里插入图片描述

大文件写HSSF

  • 优点:过程中写入缓存,不操作磁盘,最后一次性写入磁盘,速度快
  • 缺点:最多只能处理65535行,否则会抛出异常:
java.lang.IlleaglArgumentException:Invalid row number(65535) outside allowable rang (0..65535)
  • 代码截图:(没有自己写–自己没有03版本的excel)
    在这里插入图片描述
  • 当超过65536 的时候会报错
    在这里插入图片描述

大文件写XSSF

  • 优点:可以写较大的数据量,如20万条。
  • 缺点:写数据时非常慢,非常耗内存,也会发生内存溢出,如100万条。
  @Testpublic void testWrite07BigData() throws Exception {long startTime = System.currentTimeMillis();// 1.创建一个工作簿(SXSSF优化版的07的工作簿,HSSF是03年的)Workbook workbook = new XSSFWorkbook();// 2. 创建一个工作表Sheet sheet = workbook.createSheet("我的工作表");// 3.循环写入大数据for (int i = 0; i < 100000; i++) {// 创建行Row row = sheet.createRow(i);for (int j = 0; j < 10; j++) {// 创建列jCell cell = row.createCell(j);// 给列赋值cell.setCellValue(j);}}System.out.println("完事了");// 生成一张表FileOutputStream fileOutputStream = new FileOutputStream(PATH + "07BigData.xlsx");workbook.write(fileOutputStream);fileOutputStream.close();long end = System.currentTimeMillis();System.out.println("花费了:" + (double)(end - startTime)/1000 + "秒");}

大文件写SXSSF

  • 优点:可以写非常大的数据量,如100万条甚至更多条,写数据快,占用更少的内存。
    在这里插入图片描述
  • Demo(没有多大变化,只用了SXSSFWorkbook类)
 @Testpublic void testWrite07BigData() throws Exception {long startTime = System.currentTimeMillis();// 1.创建一个工作簿(SXSSF优化版的07的工作簿,HSSF是03年的)Workbook workbook = new SXSSFWorkbook();// 2. 创建一个工作表Sheet sheet = workbook.createSheet("我的工作表");// 3.循环写入大数据for (int i = 0; i < 1000000; i++) {// 创建行Row row = sheet.createRow(i);for (int j = 0; j < 10; j++) {// 创建列jCell cell = row.createCell(j);// 给列赋值cell.setCellValue(j);}}System.out.println("完事了");// 生成一张表FileOutputStream fileOutputStream = new FileOutputStream(PATH + "07BigData.xlsx");workbook.write(fileOutputStream);fileOutputStream.close();// 清除临时文件((SXSSFWorkbook)workbook).dispose();long end = System.currentTimeMillis();System.out.println("花费了:" + (double)(end - startTime)/1000 + "秒");}

5. Excel读

  • Demo:
package com.dapeng;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.junit.Test;import java.io.FileInputStream;/*** @Description* @Author zhaopeng* @Date 2023/10/13 10:43*/
public class ExcelReadTest {String PATH = "D:\\ExcelTest\\";@Testpublic void testRead() throws Exception{// 1. 获取文件流读取文件FileInputStream inputStream = new FileInputStream(PATH + "test.xlsx");// 2. 创建一个工作簿Workbook workbook = new XSSFWorkbook(inputStream);// 3. 得到表(通过下标);Sheet sheet = workbook.getSheetAt(0);// 4. 得到行(第一行)Row row = sheet.getRow(0);// 5. 获取第一个数据Cell cell = row.getCell(0);// 6.输出数据System.out.println(cell.getStringCellValue());inputStream.close();}
}

5.1 读取遇到类型转化问题该怎么解决

@Testpublic void testReadTeyp() throws Exception {// 1. 获取文件流读取文件FileInputStream inputStream = new FileInputStream(PATH + "test.xlsx");// 2. 创建一个工作簿Workbook workbook = new XSSFWorkbook(inputStream);// 3. 得到表(通过下标);Sheet sheet = workbook.getSheetAt(0);// 4. 获取第一行标题Row rowTitle = sheet.getRow(0);//      4.1 获取标题的数量if (rowTitle != null) {// 必须掌握,拿到所有的列int cells = rowTitle.getPhysicalNumberOfCells();for (int i = 0; i < cells; i++) {Cell cell = rowTitle.getCell(i);if (cell != null) {int cellType = cell.getCellType();String cellValue = cell.getStringCellValue();System.out.print(cellValue + " | ");}}}// 获取行的总数int rowCounts = sheet.getPhysicalNumberOfRows();for (int rowNum = 1; rowNum < rowCounts; rowNum++) {// 获取每一行Row row = sheet.getRow(rowNum);if (row != null) {// 读取列int columns = rowTitle.getPhysicalNumberOfCells();for (int cellColumn = 0; cellColumn < columns; cellColumn++) {System.out.print("[" + rowNum + "-" + cellColumn + "]");// 获取每一个数据Cell cell = row.getCell(cellColumn);// 匹配列数据类型if (cell != null) {int cellType = cell.getCellType();String cellValue = "";switch (cellType) {case HSSFCell.CELL_TYPE_STRING: // 字符串System.out.print("[String]");cellValue = cell.getStringCellValue();break;case HSSFCell.CELL_TYPE_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 time = cell.getDateCellValue();// 使用工具类把日期进行转换cellValue = new DateTime(time).toString("yyyy-MM-dd HH:mm:ss");} else {// 如果不是日期格式,防止数字过长System.out.print("[转换为字符串输出]");cell.setCellType(HSSFCell.CELL_TYPE_STRING);cellValue = cell.toString();}break;case HSSFCell.CELL_TYPE_ERROR: // 错误System.out.print("[数据类型错误]");break;}System.out.println(cellValue);}}}}inputStream.close();}

5.2 遇到Excel公式怎么办

   @Testpublic void readMath() throws Exception{FileInputStream inputStream = new FileInputStream(PATH + "test.xlsx");// 读取Workbook workbook = new XSSFWorkbook(inputStream);Sheet sheet = workbook.getSheetAt(0);// 这个单元格前提有公式比如=SUM(A2:A4);Row row = sheet.getRow(4);Cell cell = row.getCell(0);// 1.拿到该工作簿的公式XSSFFormulaEvaluator formulaEvaluator = new XSSFFormulaEvaluator((XSSFWorkbook) workbook);// 输出单元格内容,先获取类型int cellType = cell.getCellType();switch (cellType){case HSSFCell.CELL_TYPE_FORMULA: //公式// 先获取公式String formula = cell.getCellFormula();System.out.println(formula); // 输出公式// 计算得到值CellValue evaluate = formulaEvaluator.evaluate(cell);System.out.println(evaluate);// 输出计算好的值String value = evaluate.formatAsString();// 把值转化为String输出System.out.println(value);break;}}

6. Easy Excel

6.1简单的写

参考官方文档:https://easyexcel.opensource.alibaba.com/docs/current/quickstart/write

  1. 导入依赖
<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.2.0-beta2</version>
</dependency>
  1. 数据来源:
  private List<Entity> data() {List<Entity> list = new ArrayList<Entity>();for (int i = 0; i < 10; i++) {Entity data = new Entity();data.setString("字符串" + i);data.setDate(new Date());data.setDoubleData(0.56);list.add(data);}return list;}
  1. 一行代码导出Excel
 // 根据List写入值@Testpublic void simpleWrite(){// 1. 当前的位置String PATH = "D:\\ExcelTest\\";String fileName= PATH + "esayExcel.xlsx";EasyExcel.write(fileName,Entity.class).sheet("easyExcel").doWrite(data());}

6.2 简单的读

参考:

  1. 先写一个类继承AnalysisEventListener并重写invoke方法,数据的处理逻辑全在这里。
package com.dapeng.DemoEntity;import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.CellExtra;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;import java.util.ArrayList;
import java.util.List;
import java.util.Map;/*** @Description* @Author zhaopeng* @Date 2023/10/13 15:31*/
// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
@Slf4j
public class DemoDataListener extends AnalysisEventListener<DemoData> {/*** 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收*/private static final int BATCH_COUNT = 5;List<DemoData> list = new ArrayList<>();private DemoDAO demoDAO;public DemoDataListener() {// 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数demoDAO = new DemoDAO();}/*** 这个每一条数据解析都会来调用** @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()}* @param context*/@Overridepublic void invoke(DemoData data, AnalysisContext context) {log.info("解析到一条数据:{}", JSON.toJSONString(data));System.out.println("解析到一条数据:{}" +  JSON.toJSONString(data));list.add(data);// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOMif (list.size() >= BATCH_COUNT) {saveData();// 存储完成清理 listlist.clear();}}/*** 所有数据解析完成了 都会来调用** @param context*/@Overridepublic void doAfterAllAnalysed(AnalysisContext context) {// 这里也要保存数据,确保最后遗留的数据也存储到数据库saveData();log.info("所有数据解析完成!");}/*** 加上存储数据库*/private void saveData() {log.info("{}条数据,开始存储数据库!", list.size());demoDAO.save(list);log.info("存储数据库成功!");}
}
  1. 测试:
    /*** 最简单的读* <p>* 1. 创建excel对应的实体对象 参照{@link DemoData}* <p>* 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener}* <p>* 3. 直接读即可*/@Testpublic void simpleRead() {// 写法1:JDK8+ ,不用额外写一个DemoDataListener// since: 3.0.0-beta1String PATH = "D:\\ExcelTest\\";String fileName= PATH + "esayExcel.xlsx";// 这里默认每次会读取100条数据 然后返回过来 直接调用使用数据就行// 具体需要返回多少行可以在`PageReadListener`的构造函数设置EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/158411.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【软件测试】性能测试工具Loadrunner

文章目录 一. Loadrunner是什么二. LoadRunner的安装三. LoadRunner的使用1. Virtual User Generator(LoadRunner脚本录制)1.1 了解WebTours系统1.2 脚本录制1.3 编译1.4 运行(回放)脚本加强1. 事务插入2. 插入集合点3. 参数化4. 打印日志 2. Controller(设计测试场景)2.1 Cont…

云上攻防-云原生篇Docker安全系统内核版本漏洞CDK自动利用容器逃逸

文章目录 云原生-Docker安全-容器逃逸&内核漏洞云原生-Docker安全-容器逃逸&版本漏洞-CVE-2019-5736 runC容器逃逸-CVE-2020-15257 containerd逃逸 云原生-Docker安全-容器逃逸&CDK自动化 云原生-Docker安全-容器逃逸&内核漏洞 细节部分在权限提升章节会详解&…

DocCMS keyword SQL注入

漏洞描述 DocCMS keyword参数存在 SQL注入漏洞&#xff0c;攻击者通过漏洞可以获取数据库信息 漏洞复现 访问url&#xff1a; 漏洞证明&#xff1a; 文笔生疏&#xff0c;措辞浅薄&#xff0c;望各位大佬不吝赐教&#xff0c;万分感谢。 免责声明&#xff1a;由于传播或利…

【HTML+REACT+ANTD 表格操作】处理(改变)数据,改变DOM

博主&#xff1a;_LJaXi 专栏&#xff1a; React | 前端框架 主要是一些表格DOM操作&#xff0c;数据更换 个人向 HTML <!DOCTYPE html> <html lang"en"> <link> <meta charset"UTF-8" /> <meta name"viewport" con…

flutter入门实践2——将完成的flutter软件打包为apk

将完成的flutter软件打包为apk&#xff1a; 视频版&#xff1a; 【前端教程-Flutter篇-flutter之打包安卓版本的APP】https://www.bilibili.com/video/BV11K4y1S7Sg?vd_sourcec008a8e3bd95154e374408adc754394a 文字版&#xff1a;Flutter 打包APP &#xff08;Android &am…

JUnit5 【最实用最简洁】

JUnit5 文章目录 JUnit5一、JUnit 的相关技术二、参数化三、给测试用例指定顺序四、断言五、测试套件 安装依赖&#xff1a;在Maven库中安装 为什么学了 Selenium 还要学 JUnit&#xff1f; 1、JUnit5 是单元测试框架&#xff0c;拿着一个技术写自动化测试用例&#xff08;Sele…

想要精通算法和SQL的成长之路 - 连续的子数组和

想要精通算法和SQL的成长之路 - 连续的子数组和 前言一. 连续的子数组和1.1 最原始的前缀和1.2 前缀和 哈希表 前言 想要精通算法和SQL的成长之路 - 系列导航 一. 连续的子数组和 原题链接 1.1 最原始的前缀和 如果这道题目&#xff0c;用前缀和来算&#xff0c;我们的思路…

vue 本地上传Excel文件并读取内容

陌路遇见&#xff0c;陌路告别&#xff0c;陌路问好&#xff0c;九月再见&#xff0c;十月重现! 首先我来讲解一下我的思路&#xff1a; 首先&#xff0c;在模板部分&#xff0c;我们有以下元素&#xff1a; <input type“file” change“handleFileUpload” accept“.xlsx…

ODrive移植keil(七)—— 插值算法和偏置校准

目录 一、角度读取1.1、硬件接线1.2、程序演示1.3、代码说明 二、锁相环和插值算法2.1、锁相环2.2、插值2.3、角度补偿 三、偏置校准3.1、硬件接线3.2、官方代码操作3.3、移植后的代码操作3.4、代码说明3.5、SimpleFOC的偏置校准对比 ODrive、VESC和SimpleFOC 教程链接汇总&…

蓝桥杯(等差素数列,C++)

思路&#xff1a; 1、因为找的是长度为10&#xff0c;且公差最小的等差素数列&#xff0c;直接用枚举即可。 2、枚举用三重循环&#xff0c;第一重枚举首项&#xff0c;第二重枚举公差&#xff0c;第三重因为首项算一个&#xff0c;所以枚举九个等差素数。 代码&#xff1a;…

《从菜鸟到大师之路 正则表达式 篇》

《从菜鸟到大师之路 正则表达式 篇》 正则表达式是一个强大的文本匹配工具。但是&#xff0c;对于前端初学者来说&#xff0c;众多的符号和规则可能让人难以理解。其实&#xff0c;你不需要记住所有的正则表达式语法&#xff01;本文将分享一些简单而实用的技巧&#xff0c;帮…

ShopXO download 任意文件读取

漏洞描述 ShopXO存在任意文件读取漏洞&#xff0c;攻击者可利用该漏洞获取敏感信息 漏洞复现 访问url&#xff1a; 构造payload 漏洞证明&#xff1a; 文笔生疏&#xff0c;措辞浅薄&#xff0c;望各位大佬不吝赐教&#xff0c;万分感谢。 免责声明&#xff1a;由于传播或…

动态内存管理(malloc calloc realloc free)--- C语言

文章目录 写在前面1. malloc 和 free函数1.1 malloc函数介绍1.2 free函数介绍 2. calloc函数3. realloc函数4. 常见的动态内存错误4.1 对NULL指针的解引用操作4.2 对动态开辟空间的越界访问4.3 对非动态开辟内存使用free释放4.4 使用free释放一块动态开辟内存的一部分4.5 对同一…

低代码提速应用开发

低代码介绍 低代码平台是指一种能够帮助企业快速交付业务应用的平台。自2000年以来&#xff0c;低代码市场一直充斥着40大大小小的各种玩家&#xff0c;比如国外的Appian、K2、Pega Systems、Salesforce和Ultimus&#xff0c;国内的H3 BPM。 2015年以后&#xff0c;这个市场更是…

linux 安装python django pip 遇到的问题

Python解决SSL不可用问题 解决方案&#xff1a; 首先要明白python版本需要和openssl的版本需要相对匹配的&#xff0c;在Python3.7之后的版本&#xff0c;依赖的openssl&#xff0c;必须要是1.1或者1.0.2之后的版本&#xff0c;或者安装了2.6.4之后的libressl&#xff0c;linux…

centos7下安装elasticsearch7.8.1并配置远程连接

1、下载安装包 sudo wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.8.1-linux-x86_64.tar.gz 2、解压 sudo tar -zxvf elasticsearch-7.8.1-linux-x86_64.tar.gz 3、添加用户并设置密码 sudo useradd es sudo passwd es # 设置密码 Lida15…

Pycharm 2023 设置远程调试

pycharm 版本 &#xff1a; 2023.2.1 整体流程参考&#xff1a;https://blog.csdn.net/xuanhaolaile/article/details/128293254 首先确定远程服务器上已经安装好 requirements.txt 中所需的依赖包。 1、SSH Configurations 添加远程服务器 2、Python Interpreter 注意&…

Leetcode算法解析——查找总价格为目标值的两个商品

1. 题目链接&#xff1a;LCR 179. 查找总价格为目标值的两个商品 2. 题目描述&#xff1a; 商品价格按照升序记录于数组 price。请在购物车中找到两个商品的价格总和刚好是 target。若存在多种情况&#xff0c;返回任一结果即可。 示例 1&#xff1a; 输入&#xff1a;price …

Linux信号 signal()编程

在Linux的进程间通信中可以用signal&#xff08;&#xff09;函数进行信号与信息传递。 1.信号 信号的名字和编号&#xff1a; 每个信号都有一个名字和编号&#xff0c;这些名字都以“SIG”开头&#xff0c;例如“SIGIO ”、“SIGCHLD”等等。 信号定义在signal.h头文件中&am…

虚幻阴影整理

虚拟阴影贴图&#xff08;VSM&#xff09;是一种全新的阴影贴图方法&#xff0c;可以提供稳定的高分辨率阴影。通过与虚幻引擎5的Nanite虚拟几何体、Lumen全局光照和反射以及世界分区功能结合使用&#xff0c;它能够实现电影级的品质效果&#xff0c;为大型开放场景提供光照。 …