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

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

简介

      image.png



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 是声明的静态类变量,是基础的文件路径

image.png

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("文件生成完毕!");
    }

运行结果

image.png



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("文件生成完毕!");
    }


运行结果


image.png


大文件写入

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");
    }

image.png

总结

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();
    }
相关实践学习
简单用户画像分析
本场景主要介绍基于海量日志数据进行简单用户画像分析为背景,如何通过使用DataWorks完成数据采集 、加工数据、配置数据质量监控和数据可视化展现等任务。
SaaS 模式云数据仓库必修课
本课程由阿里云开发者社区和阿里云大数据团队共同出品,是SaaS模式云原生数据仓库领导者MaxCompute核心课程。本课程由阿里云资深产品和技术专家们从概念到方法,从场景到实践,体系化的将阿里巴巴飞天大数据平台10多年的经过验证的方法与实践深入浅出的讲给开发者们。帮助大数据开发者快速了解并掌握SaaS模式的云原生的数据仓库,助力开发者学习了解先进的技术栈,并能在实际业务中敏捷的进行大数据分析,赋能企业业务。 通过本课程可以了解SaaS模式云原生数据仓库领导者MaxCompute核心功能及典型适用场景,可应用MaxCompute实现数仓搭建,快速进行大数据分析。适合大数据工程师、大数据分析师 大量数据需要处理、存储和管理,需要搭建数据仓库?学它! 没有足够人员和经验来运维大数据平台,不想自建IDC买机器,需要免运维的大数据平台?会SQL就等于会大数据?学它! 想知道大数据用得对不对,想用更少的钱得到持续演进的数仓能力?获得极致弹性的计算资源和更好的性能,以及持续保护数据安全的生产环境?学它! 想要获得灵活的分析能力,快速洞察数据规律特征?想要兼得数据湖的灵活性与数据仓库的成长性?学它! 出品人:阿里云大数据产品及研发团队专家 产品 MaxCompute 官网 https://www.aliyun.com/product/odps&nbsp;
相关文章
|
18小时前
|
XML 前端开发 Oracle
16:JSP简介、注释与Scriptlet、Page指令元素、Include操作、内置对象、四种属性-Java Web
16:JSP简介、注释与Scriptlet、Page指令元素、Include操作、内置对象、四种属性-Java Web
8 2
|
2天前
|
存储 NoSQL 安全
java 中通过 Lettuce 来操作 Redis
java 中通过 Lettuce 来操作 Redis
java 中通过 Lettuce 来操作 Redis
|
2天前
|
分布式计算 DataWorks Java
DataWorks操作报错合集之在使用MaxCompute的Java SDK创建函数时,出现找不到文件资源的情况,是BUG吗
DataWorks是阿里云提供的一站式大数据开发与治理平台,支持数据集成、数据开发、数据服务、数据质量管理、数据安全管理等全流程数据处理。在使用DataWorks过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
16 0
|
2天前
|
Java 测试技术 Python
《手把手教你》系列技巧篇(三十六)-java+ selenium自动化测试-单选和多选按钮操作-番外篇(详解教程)
【4月更文挑战第28天】本文简要介绍了自动化测试的实战应用,通过一个在线问卷调查(&lt;https://www.sojump.com/m/2792226.aspx/&gt;)为例,展示了如何遍历并点击问卷中的选项。测试思路包括找到单选和多选按钮的共性以定位元素,然后使用for循环进行点击操作。代码设计方面,提供了Java+Selenium的示例代码,通过WebDriver实现自动答题。运行代码后,可以看到控制台输出和浏览器的相应动作。文章最后做了简单的小结,强调了本次实践是对之前单选多选操作的巩固。
11 0
|
3天前
|
分布式计算 DataWorks 监控
DataWorks操作报错合集之DataWorks在调用java sdk的createFile功能时报错com.aliyuncs.exceptions.ClientException: 1201111000 如何解决
DataWorks是阿里云提供的一站式大数据开发与治理平台,支持数据集成、数据开发、数据服务、数据质量管理、数据安全管理等全流程数据处理。在使用DataWorks过程中,可能会遇到各种操作报错。以下是一些常见的报错情况及其可能的原因和解决方法。
9 1
|
3天前
|
存储 前端开发 测试技术
《手把手教你》系列技巧篇(三十五)-java+ selenium自动化测试-单选和多选按钮操作-下篇(详解教程)
【4月更文挑战第27天】本文介绍了使用Java+Selenium进行Web自动化测试时,如何遍历和操作多选按钮的方法。文章分为两个部分,首先是一个本地HTML页面的示例,展示了多选按钮的HTML代码和页面效果,并详细解释了遍历多选按钮的思路:找到所有多选按钮的共同点,通过定位这些元素并放入list容器中,然后使用for循环遍历并操作。 第二部分介绍了在JQueryUI网站上的实战,给出了被测网址,展示了代码设计,同样使用了findElements()方法获取所有多选按钮并存储到list中,然后遍历并进行点击操作。最后,文章对整个过程进行了小结,并推荐了作者的其他自动化测试教程资源。
12 0
|
4天前
|
数据挖掘 数据库连接 数据处理
精通Excel意味着熟练掌握基础及进阶操作
精通Excel意味着熟练掌握基础及进阶操作,如数据透视表、VBA编程和自定义公式。提升效率的技巧包括善用快捷键、自动化重复任务、巧用公式与函数(如SUM和VLOOKUP)、利用数据透视表分析数据、设置条件格式、建立数据库连接、编写自定义函数、创建数据图表、使用模板和进行分组汇总。这些方法能有效提升数据分析和处理能力,优化工作效率。
12 2
|
5天前
|
前端开发 测试技术 Python
《手把手教你》系列技巧篇(三十三)-java+ selenium自动化测试-单选和多选按钮操作-上篇(详解教程)
【4月更文挑战第25天】本文介绍了自动化测试中如何处理单选和多选按钮的操作,包括它们的定义、HTML代码示例以及如何判断和操作这些元素。文章通过一个简单的HTML页面展示了单选和多选框的示例,并提供了Java+Selenium实现的代码示例,演示了如何检查单选框是否选中以及如何进行全选操作。
12 0
|
7天前
|
Java
【java基础】File操作详解
【java基础】File操作详解
8 0
|
7天前
【POI】常用excel操作方法
【POI】常用excel操作方法
12 1

推荐镜像

更多