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
原文地址:https://www.cnblogs.com/blackblack/p/13798474.html