zoukankan      html  css  js  c++  java
  • POI导入导出基本操作

    POI

    什么是POI

    POI是Apache软件基金会用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程序对Microsoft Office格式档案读和写的功能。POI为“Poor Obfuscation Implementation”的首字母缩写,意为“简洁版的模糊实现”。
    所以POI的主要功能是可以用Java操作Microsoft Office的相关文件,但是一般我们都是用来操作Excel相关文件。

    POI使用场景

    1. 将数据库信息导出为Excle表格(俗称:导出数据)
    2. 将Excel格式的文件导入到数据库里(俗称:导入数据)

    操作Excel目前比较流行的就是Apache POI和阿里的easyExcel

    基本功能

    HSSF — 提供读写Microsoft Excle格式档案的功能。 03版本

    XSSF — 提供读写Microsoft Excle OOXML格式档案的功能。 07版本

    HWPF — 提供读写Microsoft Word格式档案的功能。

    HSLF — 提供读写Microsoft PowerPoint格式档案的功能。

    HDGF — 提供读写Microsoft Visio格式档案的功能。

    Excle 03 版本和 07 版本的区别

    ①03版的excle只能放65536条,而07版本的没有限制

    ②后缀也不一样,所以操作的工具类也不同

    工作簿,工作表,行,列

    POI官网:http://poi.apache.org/index.html

    POI的使用

    首先加入POI的依赖和测试工具依赖

    <dependencies>
    <!--    xls03版本-->
        <!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.17</version>
        </dependency>
    <!--xlsx07版本-->
        <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.17</version>
        </dependency>
    <!--    日期格式化工具-->
        <!-- https://mvnrepository.com/artifact/joda-time/joda-time -->
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
            <version>2.9.9</version>
        </dependency>
    <!--    junit-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    
    </dependencies>
    

    POI-简单导出

    03版本(导出操作)

    String PATH = "D:\IDEAworkspace\POI\lr-poi";
        @Test
        public void testWrite() 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 cell3 = row2.createCell(0);
            cell3.setCellValue("统计时间");
            //创建第二行第二列 (2,2)
            Cell cell4 = row2.createCell(1);
            String time = new DateTime().toString("yyyy-MM-dd");
            cell4.setCellValue(time);
    
            //生成一张表(IO流)  03版本使用xls结尾
            FileOutputStream outputStream = new FileOutputStream(PATH + "狂神统计表03.xls");
            workbook.write(outputStream);
            //关闭流
            outputStream.close();
            System.out.println("文件生成完毕!");
        }
    

    07版本(导出操作)

      @Test
        public void testWrite1() 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 cell3 = row2.createCell(0);
            cell3.setCellValue("统计时间");
            //创建第二行第二列 (2,2)
            Cell cell4 = row2.createCell(1);
            String time = new DateTime().toString("yyyy-MM-dd");
            cell4.setCellValue(time);
    
            //生成一张表(IO流)  03版本使用xls结尾
            FileOutputStream outputStream = new FileOutputStream(PATH + "狂神统计表07.xlsx");
            workbook.write(outputStream);
            //关闭流
            outputStream.close();
            System.out.println("文件生成完毕!");
        }
    

    注意:03版本和07版本只是生成的工作簿对象和后缀不同,效果相同。

    POI-批量导出

    小文件用HSSF 03版本

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

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

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

     @Test
        public void testWrite2() throws Exception {
            //记录导出65536行数据多长时间
            long begin = System.currentTimeMillis();
            //创建一个工作簿
            HSSFWorkbook workbook = new HSSFWorkbook();
            //创建表
            HSSFSheet sheet = workbook.createSheet();
            //写入数据  此处如果rowNumber>65536就会报上边出现的错误
            for(int rowNumber = 0;rowNumber<65536;rowNumber++ ){
                HSSFRow row = sheet.createRow(rowNumber);
                for (int cellNum = 0; cellNum < 10; cellNum++) {
                    HSSFCell cell = row.createCell(cellNum);
                    cell.setCellValue(cellNum);
                }
            }
            FileOutputStream outputStream = new FileOutputStream(PATH+"测试03.xls");
            workbook.write(outputStream);
            //关闭资源
            outputStream.close();
            long end = System.currentTimeMillis();
            System.out.println("03版本多少秒"+((double)(end-begin)/1000)); //1.947秒
        }
    

    大文件用XSSF 07版本

    缺点:写数据时速度非常慢,非常消耗内存,也会发生内存溢出,如100万条数据

    优点:可以写较大的数据量,如20万条

        @Test
        public void testWrite3() throws Exception {
            //记录导出65536行数据多长时间
            long begin = System.currentTimeMillis();
            //创建一个工作簿
            XSSFWorkbook workbook = new XSSFWorkbook();
            //创建表
            XSSFSheet sheet = workbook.createSheet();
            //写入数据  此时可以写入的数据可以超过65536
            for(int rowNumber = 0;rowNumber<65536;rowNumber++ ){
                XSSFRow row = sheet.createRow(rowNumber);
                for (int cellNum = 0; cellNum < 10; cellNum++) {
                    XSSFCell cell = row.createCell(cellNum);
                    cell.setCellValue(cellNum);
                }
            }
            FileOutputStream outputStream = new FileOutputStream(PATH+"测试07.xlsx");
            workbook.write(outputStream);
            //关闭资源
            outputStream.close();
            long end = System.currentTimeMillis();
            System.out.println("07版本多少秒"+((double)(end-begin)/1000)); //8.705秒
        }
    

    SXSSF 是07版本的加强版 可写入数据更多,速度更快

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

    注意:

    过程中会产生临时文件,需要清理临时文件

    默认有100条记录被保存在内存中,如果超过这个数量,则最前面的数据被写入临时文件

    如果想自定义内存中数据的数量,可以使用new SXSSFWorkbook(数量)

        @Test
        public void testWrite4() throws Exception {
            //记录导出65536行数据多长时间
            long begin = System.currentTimeMillis();
            //创建一个工作簿
            SXSSFWorkbook workbook = new SXSSFWorkbook();
            //创建表
            SXSSFSheet sheet = workbook.createSheet();
            //写入数据
            for(int rowNumber = 0;rowNumber<100000;rowNumber++ ){
                SXSSFRow row = sheet.createRow(rowNumber);
                for (int cellNum = 0; cellNum < 10; cellNum++) {
                    SXSSFCell cell = row.createCell(cellNum);
                    cell.setCellValue(cellNum);
                }
            }
            FileOutputStream outputStream = new FileOutputStream(PATH+"测试加速版07.xlsx");
            workbook.write(outputStream);
            //关闭资源
            outputStream.close();
            //清除临时文件
            workbook.dispose();
            long end = System.currentTimeMillis();
            System.out.println("07加强版本多少秒"+((double)(end-begin)/1000)); //2.443秒
        }
    

    总结:同样是导出65536行数据,03版本用时1.947秒而07版本用时8.705秒,而导出10万条数据07加强版本用时2.443秒。

    POI导入

    03版本

     @Test
        public void read1() throws Exception {
            //1.获取文件流
            FileInputStream inputStream = new FileInputStream(PATH+"狂神统计表03.xls");
            //2.创建工作簿
            HSSFWorkbook workbook = new HSSFWorkbook(inputStream);
            //3.得到表
            HSSFSheet sheetAt = workbook.getSheetAt(0);
            //4.得到行
            HSSFRow row = sheetAt.getRow(0);
            //5.得到列
            HSSFCell cell = row.getCell(0);
            //读取值得时候,一定要注意类型
            //cell.getNumericCellValue()获取数字类型
            System.out.println(cell.getStringCellValue()); //获取字符串类型
            //关闭流
            inputStream.close();
        }
    

    07版本

    @Test
    public void read1() throws Exception {
        //1.获取文件流
        FileInputStream inputStream = new FileInputStream(PATH+"狂神统计表07.xlsx");
        //2.创建工作簿
        Workbook workbook = new XSSFWorkbook(inputStream);
        //3.得到表
        Sheet sheetAt = workbook.getSheetAt(0);
        //4.得到行
        Row row = sheetAt.getRow(0);
        //5.得到列
        Cell cell = row.getCell(0);
        System.out.println(cell.getStringCellValue());
        //关闭流
        inputStream.close();
    }
    

    在做导入的时候报了一个错误:

    org.apache.poi.openxml4j.exceptions.OLE2NotOfficeXmlFileException: The supplied data appears to be in the OLE2 Format. You are calling the part of POI that deals with OOXML (Office Open XML) Documents. You need to call a different part of POI to process this data (eg HSSF instead of XSSF)
    

    错误原因:XSSF是用来解析07版本,我却用来解析了03版本,不同版本的excle要使用对应的实现类进行解析。

    导入不同的数据类型(也可以叫做通用导入)

    Excle文件数据

     @Test
        public void read2() throws Exception {
            //1.获取文件流
            FileInputStream inputStream = new FileInputStream("D:\IDEAworkspace\POI\账单.xlsx");
            //2.创建一个工作簿
            Workbook workbook = new XSSFWorkbook(inputStream);
            Sheet sheet = workbook.getSheetAt(0);
            //3.获取标题内容
            Row rowTitle = sheet.getRow(0);
            if (rowTitle!=null){
                //rowTitle.getPhysicalNumberOfCells()是获取这一行一共有多少列
                int cellCount = rowTitle.getPhysicalNumberOfCells();
                for (int cellNumber = 0; cellNumber < cellCount; cellNumber++) {
                    Cell cell = rowTitle.getCell(cellNumber);
                    if (cell!=null){
                        System.out.print(cell.getStringCellValue()+" | ");  //手机号 | 消费日期 | 小票号 | 商品编号 | 商品条码 | 商品名称 | 商品单位 | 原价 | 销售价 | 销售数量 | 销售金额 |
                    }
                }
                System.out.println();
            }
    
            //获取表中的内容
            //sheet.getPhysicalNumberOfRows(); 获取这个表中一共有多少行
            int rowCount = sheet.getPhysicalNumberOfRows();
            //因为第一行为标题,所以rowNuber要从第二行开始
            for (int rowNumber = 1; rowNumber < rowCount; rowNumber++) {
                Row rowData = sheet.getRow(rowNumber);
                if (rowData!=null){
                    int cellCount = rowTitle.getPhysicalNumberOfCells();
                    for (int cellNumber = 0; cellNumber < cellCount; cellNumber++) {
                        System.out.print("["+(rowNumber+1)+"-"+(cellNumber+1)+"]");
                        Cell cell = rowData.getCell(cellNumber);
                        //匹配列的数据类型
                        if (cell!=null){
                            int cellType = cell.getCellType();
                            String cellValue = "";
                            switch (cellType){
                                case XSSFCell.CELL_TYPE_STRING://字符串类型
                                    System.out.print("【String】");
                                    cellValue = cell.getStringCellValue();
                                    break;
                                case XSSFCell.CELL_TYPE_BOOLEAN://布尔类型
                                    System.out.print("【Boolen】");
                                    cellValue = String.valueOf(cell.getBooleanCellValue()) ;
                                    break;
                                case XSSFCell.CELL_TYPE_BLANK://空
                                    System.out.print("【Blank】");//如果是空直接输出
                                    break;
                                case XSSFCell.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("【转换为字符串输出】");
                                        cell.setCellType(XSSFCell.CELL_TYPE_STRING);
                                        cellValue = cell.toString();
                                    }
                                    break;
                                case XSSFCell.CELL_TYPE_ERROR://如果是异常类型直接输出
                                    System.out.print("【数据类型错误】");
                                    break;
                            }
                            System.out.println(cellValue);
                        }
                    }
                }
            }
            inputStream.close();
        }
    

    控制台输出:

    手机号 | 消费日期 | 小票号 | 商品编号 | 商品条码 | 商品名称 | 商品单位 | 原价 | 销售价 | 销售数量 | 销售金额 | 
    [2-1]【转换为字符串输出】1312313
    [2-2]【Date】2020-01-01
    [2-3]【String】0000012312312
    [2-4]【String】AA11
    [2-5]【String】AA11
    [2-6]【String】老坛酸菜
    [2-7]【String】坛
    [2-8]【转换为字符串输出】100
    [2-9]【转换为字符串输出】19999
    [2-10]【转换为字符串输出】777
    [2-11]【转换为字符串输出】1
    [3-1]【转换为字符串输出】123123123
    [3-2]【Date】2020-01-02
    [3-3]【String】000042345234
    [3-4]【String】BB22
    [3-5]【String】BB22
    [3-6]【String】牛肉面
    [3-7]【String】袋
    [3-8]【转换为字符串输出】200
    [3-9]【转换为字符串输出】18888
    [3-10]【转换为字符串输出】999
    [3-11]【转换为字符串输出】1
    
  • 相关阅读:
    说说委托是个什么东西,以及委托有什么用
    Fedora/Centos使用dnf/yum为Firefox安装Flash,两行命令超简单
    Debian中的NVIDIA显卡驱动安装——超简单,一行命令
    对象、字段、属性、方法、成员、接口各自含义
    C#中的字段与属性的区别及属性的作用
    C#的foreach遍历循环和隐式类型变量
    依赖注入的通俗讲解,设计低耦合的系统
    群晖moments提示错误代码117的解决方案
    群晖数据库错误解决
    解决终端录制工具asciinema 的错误
  • 原文地址:https://www.cnblogs.com/blackblack/p/13798474.html
Copyright © 2011-2022 走看看