Apache POI 实现用Java操作Excel完成读写操作

news2024/12/28 22:57:16

简介

        

 

Apache POI是一个用于操作Microsoft Office格式文件(包括xls、docx、xlsx、pptx等)的Java API库。POI全称为Poor Obfuscation Implementation,是Apache Software Foundation的一个开源项目。它提供了一组Java API,使得Java程序可以读取、写入和操作Microsoft Office格式文件。
具体来说,POI提供了以下几种主要的组件:

  • HSSF:用于读写Excel 97-2003格式的xls文件。
  • XSSF:用于读写Excel 2007格式的xlsx文件。
  • SXSSF:是Apache POI中用于处理大量数据的API,它基于XSSF,可以处理Excel 2007及以上版本的xlsx文件。SXSSF的特点在于它可以将大量数据分成多个部分进行处理,从而减少内存的占用,提高处理大量数据的效率。
  • HWPF:用于读写Word 97-2003格式的doc文件。
  • XWPF:用于读写Word 2007格式的docx文件。
  • HSLF:用于读写PowerPoint 97-2003格式的ppt文件。
  • XSLF:用于读写PowerPoint 2007格式的pptx文件。

 这里先介绍使用Apache POI 如何操作excel

环境准备

Maven仓库

  • jdk1.8
  • poi-3.9
  • poi-ooxml-3.9
  • poi-ooxml-schemas-3.9
  • xmlbeans-2.6.0
  • junit4.12
  • joda-time-2.10.1

写入Excel文件

Excel 97-2003 和 2007的区别?

  • 文件格式不同
    • Excel 97-2003使用的是 .xls格式,.xls格式采用二进制格式存储数据,
    • 而Excel 2007使用的是 .xlsx格式。而.xlsx格式采用了基于XML的压缩文件格式
  • 大小限制不同
    • Excel 97-2003的工作表大小限制为65536行、256列。
    • Excel 2007的工作表大小限制为1048576行、16384列

API介绍

  • Workbook:表示一个Excel工作簿,包括多个Sheet,提供了创建Sheet、读取Sheet、写入Sheet等方法。
  • Sheet:表示一个Excel工作表,包括多个Row,提供了读取Row、写入Row、创建Cell等方法。
  • Row:表示Excel工作表中的一行,包括多个Cell,提供了读取Cell、写入Cell等方法。
  • Cell:表示Excel工作表中的一个单元格,提供了读取单元格值、写入单元格值、设置单元格样式等方法。

小文件写入

注意:代码中的 PATH 是声明的静态类变量,是基础的文件路径

static String PATH = "D:\\poi\\";

03版本-小文件写入

//03版本-小数据写入
    @Test
    public void testWrite03() throws IOException {
        /**
         * 1.创建一个03版的工作簿
         *  HSSF-03版本
         *  XSSF=07版本
         *  SXSSF-加速处理07版本
         */
        Workbook workbook = new HSSFWorkbook();
        /**
         * 2.创建一个工作表
         *  通过工作簿来新建工作表,因为工作簿在工作表之上
         */
        Sheet sheet = workbook.createSheet("表1");
        /**
         * 3.创建一个行
         *  通过表创建行,因为表在行之上
         *  0代表第一行
         */
        Row row1 = sheet.createRow(0);
        /**
         * 4.创建单元格
         * 通过行创建单元格
         */
        Cell cell1_1 = row1.createCell(0);//第一行第一列
        cell1_1.setCellValue("id");

        Cell cell1_2 = row1.createCell(1);//第一行第二列
        cell1_2.setCellValue("name");

        Cell cell1_3 = row1.createCell(2);//第一行第三列
        cell1_3.setCellValue("birth");

        //第二行
        Row row2 = sheet.createRow(1);
        Cell cell2_1 = row2.createCell(0);//第二行第一列
        cell2_1.setCellValue(1);
        Cell cell2_2 = row2.createCell(1);//第二行第二列
        cell2_2.setCellValue("嘴哥");
        Cell cell2_3 = row2.createCell(2);//第一行第三列


        //使用 joda包创建时间
        String time = new DateTime().toString("yyyy-MM-dd");
        cell2_3.setCellValue(time);

        //生成一张表 03版本用 xls 结尾
        File file = new File(PATH+"03_1.xls");
        FileOutputStream outputStream = new FileOutputStream(file);
        //输出到本地
        workbook.write(outputStream);

        //关闭流
        outputStream.close();

        System.out.println("文件生成完毕!");
    }

运行结果 

 

07版本-小文件写入 

//07版本-小数据写入
    @Test
    public void testWrite07() throws IOException {
        /**
         * 1.创建一个03版的工作簿
         *  HSSF-03版本
         *  XSSF=07版本
         *  SXSSF-加速处理07版本
         */
        Workbook workbook = new XSSFWorkbook();
        /**
         * 2.创建一个工作表
         *  通过工作簿来新建工作表,因为工作簿在工作表之上
         */
        Sheet sheet = workbook.createSheet("表1");
        /**
         * 3.创建一个行
         *  通过表创建行,因为表在行之上
         *  0代表第一行
         */
        Row row1 = sheet.createRow(0);
        /**
         * 4.创建单元格
         * 通过行创建单元格
         */
        Cell cell1_1 = row1.createCell(0);//第一行第一列
        cell1_1.setCellValue("id");

        Cell cell1_2 = row1.createCell(1);//第一行第二列
        cell1_2.setCellValue("name");

        Cell cell1_3 = row1.createCell(2);//第一行第三列
        cell1_3.setCellValue("birth");

        //第二行
        Row row2 = sheet.createRow(1);
        Cell cell2_1 = row2.createCell(0);//第二行第一列
        cell2_1.setCellValue(1);
        Cell cell2_2 = row2.createCell(1);//第二行第二列
        cell2_2.setCellValue("嘴哥");
        Cell cell2_3 = row2.createCell(2);//第一行第三列


        //使用 joda包创建时间
        String time = new DateTime().toString("yyyy-MM-dd");
        cell2_3.setCellValue(time);

        //生成一张表 03版本用 xls 结尾
        File file = new File(PATH+"03_1.xlsx");
        FileOutputStream outputStream = new FileOutputStream(file);
        //输出到本地
        workbook.write(outputStream);

        //关闭流
        outputStream.close();

        System.out.println("文件生成完毕!");
    }

 运行结果

 

大文件写入

03版本-大文件写入

//03版本-大数据写入65536行 1400ms
    @Test
    public void testWrite03BigData() throws IOException {
        //开始时间
        long begin = System.currentTimeMillis();

        //创建一个工作簿
        Workbook workbook = new HSSFWorkbook();
        //创建表
        Sheet sheet = workbook.createSheet();
        //写入数据
        for (int rowNums = 0; rowNums < 65536; rowNums++) {
            Row row = sheet.createRow(rowNums);
            for (int cellNums = 0; cellNums < 10; cellNums++) {
                Cell cell = row.createCell(cellNums);
                cell.setCellValue(cellNums);
            }
        }
        System.out.println("over");
        FileOutputStream outputStream = new FileOutputStream(new File(PATH + "bigData03.xls"));
        workbook.write(outputStream);
        outputStream.close();

        //结束时间
        long end = System.currentTimeMillis();
        System.out.println("总用时 "+(end-begin)+"ms");
    }

07版本-大文件写入

//07版本-大数据写入65537行 6856ms
    @Test
    public void testWrite07BigData() throws IOException {
        //开始时间
        long begin = System.currentTimeMillis();

        //创建一个工作簿
        Workbook workbook = new XSSFWorkbook();
        //创建表
        Sheet sheet = workbook.createSheet();
        //写入数据
        for (int rowNums = 0; rowNums < 65537; rowNums++) {
            Row row = sheet.createRow(rowNums);
            for (int cellNums = 0; cellNums < 10; cellNums++) {
                Cell cell = row.createCell(cellNums);
                cell.setCellValue(cellNums);
            }
        }
        System.out.println("over");
        FileOutputStream outputStream = new FileOutputStream(new File(PATH + "bigData03.xlsx"));
        workbook.write(outputStream);
        outputStream.close();

        //结束时间
        long end = System.currentTimeMillis();
        System.out.println("总用时 "+(end-begin)+"ms");
    }

 运行结果

 

07升级版-大文件写入

//07升级版-大数据写入10w行 1814ms
    @Test
    public void testWrite07BigDataS() throws IOException {
        //开始时间
        long begin = System.currentTimeMillis();

        //创建一个工作簿
        Workbook workbook = new SXSSFWorkbook();
        //创建表
        Sheet sheet = workbook.createSheet();
        //写入数据
        for (int rowNums = 0; rowNums < 100000; rowNums++) {
            Row row = sheet.createRow(rowNums);
            for (int cellNums = 0; cellNums < 10; cellNums++) {
                Cell cell = row.createCell(cellNums);
                cell.setCellValue(cellNums);
            }
        }
        System.out.println("over");
        FileOutputStream outputStream = new FileOutputStream(new File(PATH + "bigData03S.xlsx"));
        workbook.write(outputStream);
        //关闭资源
        outputStream.close();
        //关闭临时文件
        ((SXSSFWorkbook)workbook).dispose();

        //结束时间
        long end = System.currentTimeMillis();
        System.out.println("总用时 "+(end-begin)+"ms");
    }

 总结

  • HSSF:适用于读写Excel 97-2003格式的xls文件,可以处理一般大小的数据,缺点是处理大量数据时,会占用大量内存,导致程序运行较慢
  • XSSF:适用于读写Excel 2007及以上版本的xlsx文件,支持更多的行列数、更好的样式支持等,但处理大量数据时,仍然会占用大量内存,不适合处理大数据量的情况
  • SXSSF:基于XSSF,适用于处理大量数据,可以将大量数据分成多个部分进行处理,从而减少内存的占用,提高处理大量数据的效率。但不支持公式计算等高级功能。

综上,选择API应根据具体的需求和数据量来决定。如果处理的数据量较小,可以选择HSSF或XSSF;如果需要处理大量数据,可以选择SXSSF。如果需要同时兼顾处理大量数据和高级功能,可以考虑使用HSSF或XSSF与SXSSF结合的方式来处理数据。

 

03版-文件读取

@Test
    public void testRead03() throws IOException {

        //获取文件流
        FileInputStream inputStream = new FileInputStream(new File(PATH+"03_1.xls"));

        //1.创建一个工作簿,使用excel能操作的,它都可以操作
        Workbook workbook = new HSSFWorkbook(inputStream);
        //2.获取表
        Sheet sheet0 = workbook.getSheetAt(0);
        //3.得到行
        Row row = sheet0.getRow(1);//获取第1行
        //4.得到列
        Cell cell = row.getCell(0);//获取第一行第一列
        //以Number形式输出-可以选择格式
        //必须对应格式-number类型不可以转为String类型!!
        System.out.println(cell.getNumericCellValue());
        //关闭流资源
        inputStream.close();

    }

07版本-文件读取

@Test
    public void testRead07() throws IOException {

        //获取文件流
        FileInputStream inputStream = new FileInputStream(new File(PATH+"03_1.xlsx"));

        //1.创建一个工作簿,使用excel能操作的,它都可以操作
        Workbook workbook = new XSSFWorkbook(inputStream);
        //2.获取表
        Sheet sheet0 = workbook.getSheetAt(0);
        //3.得到行
        Row row = sheet0.getRow(1);//获取第1行
        //4.得到列
        Cell cell = row.getCell(0);//获取第一行第一列
        //以Number形式输出-可以选择格式
        //必须对应格式-number类型不可以转为String类型!!
        System.out.println(cell.getNumericCellValue());
        //关闭流资源
        inputStream.close();

    }

不同类型数据的读取

针对字符串、数值类型、日期等需要不同的处理方式。

//测试读取不同类型的数据 03版本
    @Test
    public void testCellType() throws IOException {
        FileInputStream inputStream = new FileInputStream(new File(PATH+"test03.xls"));

        Workbook workbook = new HSSFWorkbook(inputStream);

        Sheet sheet = workbook.getSheetAt(0);

        //读取标题内容
        Row title = sheet.getRow(0);
        if (title != null){
            int columns = title.getPhysicalNumberOfCells();//列数
            for (int cellNum = 0; cellNum < columns; cellNum++) {
                Cell cell = title.getCell(cellNum);
                if (cell != null){
                    int cellType = cell.getCellType();//我们已知为String
                    String cellValue = cell.getStringCellValue();
                    System.out.print(cellValue+" | ");
                }
            }
            System.out.println();
        }

        //读取表中的内容
        int rows = sheet.getPhysicalNumberOfRows();//行数
        for (int rowNum = 1; rowNum < rows; rowNum++) {
            Row row = sheet.getRow(rowNum);
            if (row != null){
                //读取行中的列
                int columns = title.getPhysicalNumberOfCells();
                for (int col = 0; col < columns; col++) {
                    System.out.print("["+(rowNum+1)+"-"+(col+1)+"]");
                    Cell cell = row.getCell(col);
                    //匹配列的数据类型
                    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_NUMERIC://数字(日期、数字)
                                if (HSSFDateUtil.isCellDateFormatted(cell)){//日期
                                    System.out.print("[DATE]");
                                    Date date = cell.getDateCellValue();
                                    cellValue = new DateTime(date).toString("yyyy-MM-dd");
                                }else{
                                    System.out.print("[NUMBER]");
                                    //防止数字过长,转为String
                                    cell.setCellType(HSSFCell.CELL_TYPE_STRING);
                                    cellValue = cell.toString();
                                }
                                break;
                            case HSSFCell.CELL_TYPE_BLANK://空
                                System.out.print("[NULL]");
                                break;
                            case HSSFCell.CELL_TYPE_BOOLEAN://布尔
                                System.out.print("[BOOLEAN]");
                                cellValue = String.valueOf(cell.getBooleanCellValue());
                            case HSSFCell.CELL_TYPE_ERROR:
                                System.out.print("[ERROR]");
                                cellValue = String.valueOf(cell.getErrorCellValue());
                                break;
                        }
                        System.out.println(cellValue);
                    }
                }
            }
        }
        inputStream.close();
    }

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LLM_StableDiffusion_studio发布

背景&#xff1a; 从chatgpt发布到现在已经超过半年时间&#xff0c;AGI的势头越来越猛。大家都在做各种的尝试和组合&#xff0c;把chatgpt通用的强大的知识表达和理解能力尝试应用在自己的业务场景。前期也是出现非常多的业务应用&#xff0c;但是主要还是围绕chatgpt本身已…

循环神经网络(RNN)简单介绍—包括TF和PyTorch源码,并给出详细注释

文章目录 循环神经网络&#xff08;RNN&#xff09;入门教程1. 循环神经网络的原理2. 循环神经网络的应用3. 使用keras框架实现循环神经网络3.1导入对应的库及加载数据集3.2.数据预处理3.3定义RNN模型3.4训练模型3.5测试模型 4.使用PyTorch框架实现上述功能—注释详细5.结论 循…

动静态库的制作和使用

动静态库 一&#xff0c;什么是库二&#xff0c;静态库的制作静态库原理 三&#xff0c;动态库的制作四&#xff0c;动态库的配置五&#xff0c;动态库的加载 一&#xff0c;什么是库 &#x1f680;库这个东西我们一直在使用&#xff0c;举个简单了例子&#xff0c;无论你是用…

netplan, NetworkManager, systemd-networkd简介

1、systemd-networkd简介 systemd-networkd是systemd 的一部分 &#xff0c;负责 systemd 生态中的网络配置部分(systemd-networkd.service, systemd-resolved.service)。使用 systemd-networkd&#xff0c;你可以为网络设备配置基础的 DHCP/静态IP网络等&#xff0c;还可以配…

U8W/U8W-Mini使用与常见问题解决

U8W/U8W-Mini使用与常见问题解决 U8WU8W/U8W-mini简介准备工作U8W/U8W-mini在线联机下载U8W/U8W-mini脱机下载第一步&#xff0c;把程序下载到U8W/U8W-mini烧录器中&#xff1a;第二步&#xff0c;用U8W/U8W-mini烧录器给目标单片机脱机下载 U8W/U8W-mini烧录器使用中常见的问题…

初识Linux运维

一.初识Linux 1.Linux系统内核 内核提供了Linux系统的主要功能&#xff0c;如硬件调度管理的能力。 Linux内核是免费开源的&#xff0c;任何人都可以查看内核的源代码&#xff0c;甚至是贡献源代码。 2.Linux系统发行版 内核无法被用户直接使用&#xff0c;需要配合应用程…

淘宝iOS拍立淘微距能力探索与实现

画面模糊问题的源头也是来自用户的微距体验不佳&#xff0c;我们对问题深入分析&#xff0c;适当拆解。通过 Apple Development Doc 的查阅及实践&#xff0c;一步步抽丝剥茧&#xff0c;最终完美解决用户的体验痛点&#xff0c;也为我们自身沉淀了展示微距的能力。 前言 在最近…

Unix和Linux

UNIX 诞生于 20 世纪 60 年代末 Windows 诞生于 20 世纪 80 年代中期 Linux 诞生于 20 世纪 90 年代初 1965 年&#xff0c;贝尔实验室、美国麻省理工学院和通用电气公司联合发起了Multics 工程计划&#xff0c;目标是开发一种交互式的、具有多道程序处理能力的分时操作系统&a…

NTP服务与SSH服务

NTP&#xff1a;时间同步服务&#xff0c;采用UDP协议&#xff0c;端口号为123。 配置NTP时间服务器&#xff0c;确保客户端主机能和服务主机同步时间 首先&#xff0c;我们必须确保服务端与客户端在同一时区。 更改时区&#xff1a;timedatectl set-timezone asia/shanghai …

隋唐洛阳“西宫”:上阳宫的GIS视角

隋唐洛阳城简介 营建 隋大业元年&#xff08;605年&#xff09;&#xff0c;在隋炀帝的授意下&#xff0c;隋代著名城市设计师宇文恺&#xff0c;在汉魏故城以西重新选址&#xff0c;历时8个月&#xff0c;日役劳工200万&#xff0c;兴建新都洛阳城。 城和苑 隋唐洛阳城采用…

页面注册案例

效果图&#xff1a; 分析业务模块&#xff1a; 发送验证码模块各个表单验证模块勾选已经阅读同意模块下一步验证全部模块&#xff1a;只要上面有一个input验证不通过就不同意提交 业务 1 &#xff1a;发送验证码 用户点击之后&#xff0c;显示05秒后重新获取时间到了&…

大国护眼学习笔记01

第一天&#xff08;23.4.17&#xff09; 2—11节什么是近视&#xff1f; 1、“近视离焦”是指成像点落在视网膜的哪里&#xff1f; 前面 2、“远视离焦”是指成像点落在视网膜的哪里&#xff1f; 后面 3、眼轴变长时&#xff0c;成像点会往前移还是往后移&#xff1f; 前移 4、…

毛灵栋 : 以兴趣为壤,育能力之实 | 提升之路系列(一)

导读 为了发挥清华大学多学科优势&#xff0c;搭建跨学科交叉融合平台&#xff0c;创新跨学科交叉培养模式&#xff0c;培养具有大数据思维和应用创新的“π”型人才&#xff0c;由清华大学研究生院、清华大学大数据研究中心及相关院系共同设计组织的“清华大学大数据能力提升项…

【RP-RV1126】Ubuntu上配置Buildroot Qt 开发板远程开发调试环境(SSH)

文章目录 一、前提二、基础设置建设Buildroot编译Qt5配置SSHBuildroot文件系统添加账号密码开发板联网Buildroot文件系统构建时打开rsync功能 三、QtCreator配置3.1 配置Qt交叉编译套件(Kits)配置Kits里面的交叉编译器配置Kits里面的qmake工具最后配置Kits 3.2 配置远程部署设备…

VLAN基础实验

实验要求&#xff1a; 1、PC1和PC3所在接口为Access接口 PC2/4/5/6处于同一网段:其中PC2可以访问PC4/5/6 PC4可以访问PC5&#xff0c;但不能访问PC6 PC5不能访问PC6 2、PC1/3与PC2/4/5/6不再同一网段 3、所有PC通过DHCP获取IP地址&#xff0c;且PC1/3可以正常访问PC2/4/5/6 实…

tkinter-TinUI-xml实战(9)crosschat客户端

tkinter-TinUI-xml实战&#xff08;9&#xff09;crosschat客户端 引言声明文件结构核心代码服务端连接登录界面主页面主文件 结语 引言 CrossChat&#xff08;十字街&#xff09;是一个线上匿名群聊平台&#xff0c;类似Hack.Chat。 现在通过websocket简单地构建一个cc的客户…

随机蛙跳算法 (SFLA)简单实现(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 随着计算机科学与技术的迅速发展,人类生存空间的扩大以及认识与改造世界范围的拓宽,人们对科学技术提出了新的和更高的要求,其…

android中线程池的选择

线程池是把一个或多个线程通过统一的方式进行调度和重复使用的技术。 避免了因为线程过多而带来使用上的开销。 在安卓开发中&#xff0c;为了更好的性能体验&#xff0c;我们在选择线程池的时候&#xff0c;需要从具体需求来考虑&#xff0c;主要考虑以下几方面&#xff1a; …

计算机类专业的普通校招生毕业如何“卷”一份好工作?

毕业差不多两年的校招生有感 一、为什么写这篇文章&#xff1f;二、我 → 一名普通的校招生前身三、我 → 一名普通的校招生养成四、校招如何拿到offer&#xff1f;五、总结 一、为什么写这篇文章&#xff1f; 一开始我写CSDN是为了记录自己学习技术的小日记&#xff0c;小总结…

JavaScript运算符与表达式

目录 一、 二、|| 三、??与?. ?? ?. 四、... 五、[] {} [] {} 一、 严格相等运算符&#xff0c;用作逻辑判断 1 1 // 返回 true 1 1 // 返回 true&#xff0c;会先将右侧的字符串转为数字&#xff0c;再做比较 1 1 // 返回 false&#xff0c;类型不等…