【狂神说Java】POI技术详解

这篇具有很好参考价值的文章主要介绍了【狂神说Java】POI技术详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

链接: 面试题库

https://www.bloghut.cn/questionBank

【狂神说Java】POI技术详解


1、常用信息

  (1)、将用户信息导出为excel表格(导出数据…)

  (2)、将Excel表中的信息录入到网站数据库(习题上传…)

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

是什么:组件,工具

  Apache POI 是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程式对Microsoft Office格式档案读和写的功能。


2、Apache POI

官网:

https://poi.apache.org/

【狂神说Java】POI技术详解


3、easyExcel

官网:

https://www.yuque.com/easyexcel/doc/easyexcel

  Java领域解析,生成Excel比较有名的框架有Apache poi,jxl等,但他们都存在一个严重的问题就是非常的耗内存,如果你的系统并发量不大的话可能还行,但是一旦并发上来后一定会OOM或者JVM频繁的full gc.

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

  EasyExcel采用一行一行的解析模式,并将一行的解析结果以观察者的模式通知处理(AnalysisEventListener)。

【狂神说Java】POI技术详解


4、xls和xlsx区别

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

最大行列得数量不同:

  xls最大只有65536行、256列

  xlsx可以有1048576行、16384列

        <!--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>

poi 操作xls的
poi-ooxml 操作xlsx的

操作的版本不同,使用的工具类也不同

【狂神说Java】POI技术详解
工作簿:
工作表:
行:
列:


5、POI Excel 写 03和07版本方式

5.1小数据量

package cn.bloghut;

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.jupiter.api.Test;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.Date;

/**
 * @Classname ExcelWrite
 * @Description TODO
 * @Date 2022/1/7 12:41
 * @Created by 闲言
 */
public class ExcelWrite {

    String PATH = "G:\\狂\\POIStudy\\xy-poi";

    /**
     * 写工作簿 03版本
     */
    @Test
    public void Write03() throws Exception {
        //1.创建一个工作簿
        Workbook workbook = new HSSFWorkbook();
        //2.创建 一个工作表
        Sheet sheet = workbook.createSheet("闲言粉丝统计表");
        //3.创建一行
        Row row1 = sheet.createRow(0);
        //4.创建一个单元格
        //(1,1)
        Cell cell1 = row1.createCell(0);
        cell1.setCellValue("今日新增观众");
        //(1,2)
        Cell cell2 = row1.createCell(1);
        cell2.setCellValue(666);

        //创建第二行
        Row row2 = sheet.createRow(1);
        //(2,1)
        Cell cell21 = row2.createCell(0);
        cell21.setCellValue("统计时间");
        //(2,2)
        Cell cell22 = row2.createCell(1);
        String datetime = new DateTime().toString("yyyy-MM-dd HH:mm:ss");
        cell22.setCellValue(datetime);

        //生成一张表(IO流),03版本就是使用xls结尾
        FileOutputStream fos = new FileOutputStream(PATH + "闲言观众统计表03.xls");
        //输出
        workbook.write(fos);
        //关闭流
        fos.close();
        System.out.println("文件生成完毕");
    }

    /**
     * 写工作簿 07版本
     */
    @Test
    public void Write07() throws Exception {
        //1.创建一个工作簿
        Workbook workbook = new XSSFWorkbook();
        //2.创建 一个工作表
        Sheet sheet = workbook.createSheet("闲言粉丝统计表");
        //3.创建一行
        Row row1 = sheet.createRow(0);
        //4.创建一个单元格
        //(1,1)
        Cell cell1 = row1.createCell(0);
        cell1.setCellValue("今日新增观众");
        //(1,2)
        Cell cell2 = row1.createCell(1);
        cell2.setCellValue(666);

        //创建第二行
        Row row2 = sheet.createRow(1);
        //(2,1)
        Cell cell21 = row2.createCell(0);
        cell21.setCellValue("统计时间");
        //(2,2)
        Cell cell22 = row2.createCell(1);
        String datetime = new DateTime().toString("yyyy-MM-dd HH:mm:ss");
        cell22.setCellValue(datetime);

        //生成一张表(IO流),03版本就是使用xlsx结尾
        FileOutputStream fos = new FileOutputStream(PATH + "闲言观众统计表07.xlsx");
        //输出
        workbook.write(fos);
        //关闭流
        fos.close();
        System.out.println("文件生成完毕");
    }
}

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


5.2大文件写HSSF(03)

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

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

【狂神说Java】POI技术详解

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

@Test
    public void Write03BigData() throws Exception{

        //时间
        long begin = System.currentTimeMillis();
        //1.创建一个工作簿
       Workbook workbook = new HSSFWorkbook();
        //2.创建一个表
        Sheet sheet = workbook.createSheet("第一页");
        //写入数据
        for (int rowNum = 0;rowNum<65536;rowNum++){
            //3.创建行
            Row row = sheet.createRow(rowNum);
           for (int CellNum = 0;CellNum<10;CellNum++){
               Cell cell = row.createCell(CellNum);
               cell.setCellValue(CellNum);
           }
        }
        System.out.println("over");
        //获取io流
        FileOutputStream fos = new FileOutputStream(PATH+"Write03BigData.xls");
        //生成一张表
        workbook.write(fos);
        fos.close();
        long end = System.currentTimeMillis();
        System.out.println("耗时:"+(end-begin));
    }

结果:
【狂神说Java】POI技术详解


5.3大文件写XSSF(07)

缺点:写数据时速度非常慢,非常耗内存,也会发生内存溢出,如100万条。
优点:可以写较大数据量,如20万条

    @Test
    public void Write07BigData() throws Exception{

        //时间
        long begin = System.currentTimeMillis();
        //1.创建一个工作簿
        Workbook workbook = new XSSFWorkbook();
        //2.创建一个表
        Sheet sheet = workbook.createSheet("第一页");
        //写入数据
        for (int rowNum = 0;rowNum<65537;rowNum++){
            //3.创建行
            Row row = sheet.createRow(rowNum);
            for (int CellNum = 0;CellNum<10;CellNum++){
                Cell cell = row.createCell(CellNum);
                cell.setCellValue(CellNum);
            }
        }
        System.out.println("over");
        //获取io流
        FileOutputStream fos = new FileOutputStream(PATH+"Write03BigData.xlsx");
        //生成一张表
        workbook.write(fos);
        fos.close();
        long end = System.currentTimeMillis();
        System.out.println("耗时:"+(end-begin));
    }

结果:
【狂神说Java】POI技术详解


5.4大文件写SXSSF

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

注意:

  1. 过程中会产生临时文件,需要清理临时文件
  2. 默认由100条记录被保存在内存中,如果超过这数量,则最前面的数据被写入临时文件
  3. 如果想自定义内存中数据的数量,可以使用new SXSSFWorkbook(数量)
@Test
    public void Write07BigDataS() throws Exception{

        //时间
        long begin = System.currentTimeMillis();
        //1.创建一个工作簿
        Workbook workbook = new SXSSFWorkbook();
        //2.创建一个表
        Sheet sheet = workbook.createSheet("第一页");
        //写入数据
        for (int rowNum = 0;rowNum<100000;rowNum++){
            //3.创建行
            Row row = sheet.createRow(rowNum);
            for (int CellNum = 0;CellNum<10;CellNum++){
                Cell cell = row.createCell(CellNum);
                cell.setCellValue(CellNum);
            }
        }
        System.out.println("over");
        //获取io流
        FileOutputStream fos = new FileOutputStream(PATH+"Write03BigDataS.xlsx");
        //生成一张表
        workbook.write(fos);
        fos.close();
        //清除临时文件
        ((SXSSFWorkbook) workbook).dispose();
        long end = System.currentTimeMillis();
        System.out.println("耗时:"+(end-begin));
    }

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

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


6、POI Excel读 03和07版本方式

6.1 (03版本)

 @Test
    public  void Read03() throws Exception{
        //1.获取文件流
        FileInputStream fis = new FileInputStream(PATH+"xy-poi闲言观众统计表03.xls");
        //2.创建一个工作簿。使用excel能操作的这边都可以操作!
        Workbook workbook = new HSSFWorkbook(fis);
        //3.获取表
        Sheet sheet = workbook.getSheetAt(0);
        //4.获取第一行
        Row row1 = sheet.getRow(0);
        //5.获取第一列
        Cell cell1 = row1.getCell(0);
        //6.获取第一行第一列的值
        String stringCellValue = cell1.getStringCellValue();
        //获取第二列
        Cell cell2 = row1.getCell(1);
        //获取第一行第二列的值
        double numericCellValue = cell2.getNumericCellValue();
        System.out.println(stringCellValue+" | "+numericCellValue);

        fis.close();
    }

  注意获取值的类型即可


6.2(07版本)

@Test
    public  void Read07() throws Exception{
        //1.获取文件流
        FileInputStream fis = new FileInputStream(PATH+"xy-poi闲言观众统计表07.xlsx");
        //2.创建一个工作簿。使用excel能操作的这边都可以操作!
        Workbook workbook = new XSSFWorkbook(fis);
        //3.获取表
        Sheet sheet = workbook.getSheetAt(0);
        //4.获取第一行
        Row row1 = sheet.getRow(0);
        //5.获取第一列
        Cell cell1 = row1.getCell(0);
        //6.获取第一行第一列的值
        String stringCellValue = cell1.getStringCellValue();
        //获取第二列
        Cell cell2 = row1.getCell(1);
        //获取第一行第二列的值
        double numericCellValue = cell2.getNumericCellValue();
        System.out.println(stringCellValue+" | "+numericCellValue);
        fis.close();
    }

  注意获取值的类型即可


6.3读取不同的数据类型

    @Test
    public void CellType03() throws Exception{
        //获取文件流
        FileInputStream fis = new FileInputStream(PATH+"明显表.xls");
        //获取一个工作簿
        Workbook workbook = new HSSFWorkbook(fis);
        //获取一个工作表
        Sheet sheet = workbook.getSheetAt(0);
        //获取第一行内容
        Row row = sheet.getRow(0);
        if (row != null){
            //获取所有的列
            int Cells = row.getPhysicalNumberOfCells();
            for (int col = 0;col < Cells;col++){
                //获取当前列
                Cell cell = row.getCell(col);
                if (cell != null){
                    //获取当前行的第 col 列的值
                    String cellValue = cell.getStringCellValue();
                    System.out.print(cellValue+" | ");
                }
            }
        }
        //获取标准的内容
        //获取有多少行
        int rowCount = sheet.getPhysicalNumberOfRows();
        //从1开始,第一行是标题
        for (int rowNum = 1;rowNum < rowCount;rowNum++){
            Row rowData = sheet.getRow(rowNum);
            if (rowData != null){
                //获取当前行的列数
                int cellCount = rowData.getPhysicalNumberOfCells();
                System.out.println();
                for (int col = 0;col < cellCount;col++){
                    //获取当前列的值
                    Cell cellData = rowData.getCell(col);
                    //打印当前行当前列的值
                    System.out.print("["+(rowNum+1)+"-"+(col+1)+"]");
                    //匹配列的类型
                    if (cellData != null){
                        //获取列的类型
                        int cellType = cellData.getCellType();
                        String cellValue = "";
                        switch (cellType){
                            case  Cell.CELL_TYPE_STRING://字符串
                                System.out.print("[string]");
                                cellValue = cellData.getStringCellValue();
                                break;
                            case  Cell.CELL_TYPE_BOOLEAN://布尔
                                System.out.print("[boolean]");
                                cellValue = String.valueOf(cellData.getBooleanCellValue());
                                break;
                            case  Cell.CELL_TYPE_BLANK://System.out.print("[blank]");
                                break;
                            case  Cell.CELL_TYPE_NUMERIC://数字(日期、普通数字)
                                System.out.print("[numeric]");
                                if (HSSFDateUtil.isCellDateFormatted(cellData)){
                                    //如果是日期
                                    System.out.print("[日期] ");
                                    Date date = cellData.getDateCellValue();
                                    cellValue = new  DateTime(date).toString("yyyy-MM-dd HH:mm:ss");
                                }else {
                                    //不是日期格式,防止数字过长
                                    System.out.print("[转换字符串输出] ");
                                    //转为字符串
                                    cellData.setCellType(HSSFCell.CELL_TYPE_STRING);
                                    cellValue = cellData.toString();

                                }
                                break;
                            case  Cell.CELL_TYPE_ERROR://错误
                                System.out.print("[error]");
                                break;
                        }
                        System.out.print("["+cellValue+"]\n");
                    }
                }
            }
        }

        System.out.println();
        System.out.println("over");
        fis.close();
    }

  如果是07版本的Excel ,只需要将HSSFWorkbook类修改为XSSFWorkbook类。将xls文件修改为xlsx文件即可


测试:读取以下表格内容

【狂神说Java】POI技术详解


结果:
【狂神说Java】POI技术详解


7 EasyExcel操作

7.1导入依赖

        <!--easyExcel-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>2.2.0-beta2</version>
        </dependency>

7.2写入测试

1.格式类

@Getter
@Setter
@EqualsAndHashCode
public class DemoData {
    @ExcelProperty("字符串标题")
    private String string;
    @ExcelProperty("日期标题")
    private Date date;
    @ExcelProperty("数字标题")
    private Double doubleData;
    /**
     * 忽略这个字段
     */
    @ExcelIgnore
    private String ignore;
}

2.写的方法

@Test
    public  void simpleWrite(){
        // 写法1
        String fileName = PATH+"EasyTest.xlsx";
        //write(fileName,格式类)
        //sheet(表名)
        //doWrite(数据)
        EasyExcel.write(fileName,DemoData.class).sheet("模板").doWrite(data());

    }

结果

【狂神说Java】POI技术详解


固定套路:
1、写入:固定类格式进行写入
2、读取:根据监听器设置的规则进行读取

7.3读测试

演示读取以下excel表格数据
【狂神说Java】POI技术详解

1.格式类

@Getter
@Setter
@EqualsAndHashCode
public class DemoData {
    private String string;
    private Date date;
    private Double doubleData;
}

2.监听器

package cn.bloghut.esay;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSON;

import java.util.ArrayList;
import java.util.List;

// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
public class DemoDataListener extends AnalysisEventListener<DemoData> {

    private static final int BATCH_COUNT = 100;
    private List<DemoData> cachedDataList = new ArrayList<>(BATCH_COUNT);

    private DemoDAO demoDAO;

    public DemoDataListener() {
        // 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数
        demoDAO = new DemoDAO();
    }

    public DemoDataListener(DemoDAO demoDAO) {
        this.demoDAO = demoDAO;
    }

    /**
     * 读取数据会执行invoke 方法
     * DemoData 类型
     * AnalysisContext 分析上下文
     *
     * @param data
     * @param context
     */
    @Override
    public void invoke(DemoData data, AnalysisContext context) {
        System.out.println(JSON.toJSONString(data));
        cachedDataList.add(data);
        // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
        if (cachedDataList.size() >= BATCH_COUNT) {
            saveData();
            // 存储完成清理 list
            cachedDataList.clear();
        }
    }

    /**
     * 所有数据解析完成了 都会来调用
     *
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 这里也要保存数据,确保最后遗留的数据也存储到数据库
        saveData();
        System.out.println("所有数据解析完成");
    }

    /**
     * 加上存储数据库
     */
    private void saveData() {
        System.out.println("{}条数据,开始存储数据库!"+cachedDataList.size());
        demoDAO.save(cachedDataList);
        System.out.println("存储数据库成功");
    }

}

DAO类(不操作数据库,用不到)

public class DemoDAO {
    public void save(List<DemoData> list) {
        // 如果是mybatis,尽量别直接调用多次insert,自己写一个mapper里面新增一个方法batchInsert,所有数据一次性插入
    }
}

测试

@Test
    public void simpleRead() throws Exception{
        String fileName = PATH+"EasyTest.xlsx";
        EasyExcel.read(fileName,DemoData.class,new DemoDataListener()).sheet().doRead();

    }

结果
【狂神说Java】POI技术详解文章来源地址https://www.toymoban.com/news/detail-404831.html


到了这里,关于【狂神说Java】POI技术详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于安卓Java试题库在线考试系统uniapp 微信小程序

    本文首先分析了题库app应用程序的需求,从系统开发环境、系统目标、设计流程、功能设计等几个方面对系统进行了系统设计。开发出本题库app,主要实现了学生、教师、测试卷、试题、考试等。总体设计主要包括系统功能设计、该系统里充分综合应用Mysql数据库、JAVA等相关

    2024年02月07日
    浏览(67)
  • 狂神说Docker

    思维导图 : 参考: https://blog.csdn.net/weixin_47024018/article/details/127916629 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows操作系统的机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相

    2023年04月08日
    浏览(46)
  • SpringBoot笔记——(狂神说)——待续

    路线 javase: OOPmysql:持久化 html+css+js+jquery+框架:视图,框架不熟练,css不好; javaweb:独立开发MVC三层架构的网站了∶原始 ssm :框架:简化了我们的开发流程,配置也开始较为复杂; war: tomcat运行 spring再简化: SpringBoot - jar:内嵌tomcat;微服务架构!服务越来越多: springcloud; 什么是Spring S

    2024年02月10日
    浏览(40)
  • ElasticSearch学习笔记(狂神说)

    视频地址:https://www.bilibili.com/video/BV17a4y1x7zq 在学习ElasticSearch之前,先简单了解一下Lucene: Doug Cutting开发 是apache软件基金会 jakarta项目组的一个子项目 是一个开放源代码的全文检索引擎工具包 不是一个完整的全文检索引擎,而是一个全文检索引擎的架构,提供了完整的查询

    2024年02月04日
    浏览(47)
  • Go语言学习笔记(狂神说)

    视频地址:https://www.bilibili.com/video/BV1ae41157o9 聊聊Go语言的历史-KuangStudy-文章 下面列举的是原生使用Go语言进行开发的部分项目。 Docker Docker 是一种操作系统层面的虚拟化技术,可以在操作系统和应用程序之间进行隔离,也可以称之为容器。Docker 可以在一台物理服务器上快速

    2024年02月15日
    浏览(45)
  • Git的基本使用笔记——狂神说

    版本迭代, 版本控制( Revision control)是一种在开发的过程中用于管理我们对文件、目录或工程等内容的修改历史,方便查看更改历史记录,备份以便恢复以前的版本的软件工程技术。 实现跨区域多人协同开发 追踪和记载一个或者多个文件的历史记录 组织和保护你的源代码和

    2024年02月09日
    浏览(44)
  • JUC并发编程——集合类不安全及Callable(基于狂神说的学习笔记)

    List不安全 CopyOnWriteArrayList与vector对比,以下来自CSDN智能助手的回答: Java中的CopyOnWriteArrayList和Vector都是线程安全的动态数组,可以在多线程环境下使用。 CopyOnWriteArrayList使用了一种特殊的写时复制机制,它在对数组进行修改时,会创建一个新的副本,而不是直接在原数组上

    2024年02月07日
    浏览(73)
  • 计算机网络考试试题库-期末考试题库含答案

    一、选择题(第一章 1-10;第二章 11-20;第三章21-35;第四章36-60 ;第五章 61-73道;第六章 74-84道;第七章85-90;第九章91-95;第十章96-100) 1.下列四项内容中,不属于Internet(因特网)基本功能是____D____。 A.电子邮件 B.文件传输 C.远程登录 D.实时监测控制 2.Internet是建立在____C____

    2024年02月11日
    浏览(51)
  • HarmonyOS应用开发者高级认证试题库(鸿蒙)

    目录 考试链接: 流程: 选择: 判断 单选 多选 华为开发者学堂 华为开发者学堂 https://developer.huawei.com/consumer/cn/training/dev-certification/a617e0d3bc144624864a04edb951f6c4 先进行实名认证,以确保有效 云函数打包完成后,需要到AppGallery Connect创建对应函数的触发器才可以在端侧中调用

    2024年01月17日
    浏览(63)
  • HarmonyOS应用开发者初级认证试题库(鸿蒙)

    目录 考试链接: 流程: 选择: 判断: 单选: 多选: 开发者能力认证-职业认证-鸿蒙能力认证-华为开发者学堂 (huawei.com) https://developer.huawei.com/consumer/cn/training/dev-certification/a617e0d3bc144624864a04edb951f6c4 先进行实名认证,以确保有效 1.Ability是系统调度应用的最小单元,是能够完

    2024年01月17日
    浏览(72)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包