使用代码操作Excel文件(POI)

本篇文章将讲述使用POI如何去对Excel文件进行读写

apache的POI文档:https://poi.apache.org

1.Maven导入poi包

<!--导入依赖-->
    <dependencies>
        <!--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>

        <!--日期格式化工具-->
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
            <version>2.10.1</version>
        </dependency>

        <!--junit测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

这里解释下为什么有两个版本(03版,07版) ?
1. 两者的文件后缀不同,03版本是.xls,07版本是.xlsx
2. 03版的最多只能有65536行 (03版本如果写入数据超过65536行,则会出现异常),而07版行数可以无限制 (代表07版可以存放的数据更多)

在开始代码之前,先认识下Excel表结构 直接看下图

在这里插入图片描述

2.POI进行基本的写入

注:03版本使用 HSSFWorkbook,07版本使用 XSSFWorkbook (07版本大量数据写入使用SXSSFWorkbook)
07版本的XSSFWorkbook 与 SXSSFWorkbook的区别 ?这个疑问下面会讲到。

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.junit.Test;

import java.io.FileOutputStream;

/**
 * @author: libo
 * @date: 2020/10/8  15:22
 * @motto: 即使再小的帆也能远航
 */
public class test {
    
    

    /*文件生成路径*/
    final String PATH = "D:\\IntelliJ IDEA 2019.1_File\\POIandEasyExcel\\poi\\";

    /*03版本Excel*/
    @Test
    public void poi03() throws Exception {
    
    
        /*1.创建工作簿*/
        Workbook workbook = new HSSFWorkbook();
        /*2.创建工作表*/
        Sheet sheet = workbook.createSheet("03版本");
        /*3.创建第一行(0就是第一行,以此类推 就像数组下标一样)*/
        Row row = sheet.createRow(0);
        /*4.创建一列(单元格)(0就是第一列)*/
        Cell cell = row.createCell(0);
        cell.setCellValue("第一行第一列");
        /*4.创建一列(单元格)(1就是第二列)*/
        Cell cell2 = row.createCell(1);
        cell2.setCellValue("第一行第二列");
        /*创建第二行(1就是第二行)*/
        Row row2 = sheet.createRow(1);
        /*创建(单元格)*/
        Cell cell21 = row2.createCell(0);
        cell21.setCellValue("第二行第一列");
        Cell cell22 = row2.createCell(1);
        cell22.setCellValue("第二行第二列");

        /*5.创建输出流(IO流)  03版本文件后缀为:.xls*/
        FileOutputStream fileOutputStream = new FileOutputStream(PATH + "03Excel.xls");
        /*6.生成文件*/
        workbook.write(fileOutputStream);
        /*7.关闭流*/
        fileOutputStream.close();
    }



    /*07版本Excel*/
    @Test
    public void poi07() throws Exception {
    
    
        /*1.创建工作簿*/
        Workbook workbook = new XSSFWorkbook();
        /*2.创建工作表*/
        Sheet sheet = workbook.createSheet("07版本");
        /*3.创建第一行*/
        Row row = sheet.createRow(0);
        /*4.创建一列(单元格)*/
        Cell cell = row.createCell(0);
        cell.setCellValue("第一行第一列");
        Cell cell2 = row.createCell(1);
        cell2.setCellValue("第一行第二列");
        /*创建第二行*/
        Row row2 = sheet.createRow(1);
        /*创建(单元格)*/
        Cell cell21 = row2.createCell(0);
        cell21.setCellValue("第二行第一列");
        Cell cell22 = row2.createCell(1);
        cell22.setCellValue("第二行第二列");

        /*5.创建输出流(IO流)  07版本文件后缀为:.xlsx*/
        FileOutputStream fileOutputStream = new FileOutputStream(PATH + "07Excel.xlsx");
        /*6.生成文件*/
        workbook.write(fileOutputStream);
        /*7.关闭流*/
        fileOutputStream.close();
    }
}

3.POI进行大量数据的写入

模拟下大量数据的写入,写入65536行,10列(每行10个单元格)的数据
并且记录程序所耗费的时间

    /*大量数据写入03版本Excel*/
    @Test
    public void poi03BigDate() throws Exception {
    
    

        /*记录程序开始时间*/
        long begin = System.currentTimeMillis();

        /*1.创建工作簿*/
        Workbook workbook = new HSSFWorkbook();
        /*2.创建工作表*/
        Sheet sheet = workbook.createSheet("03版本大量数据写入");

        /*x:行 y:列(单元格)*/
        for (int x = 0; x < 65536; x++) {
    
    
            /*3.创建行*/
            Row row = sheet.createRow(x);
            for (int y = 0; y < 10; y++) {
    
    
                /*4.创建列(单元格)*/
                Cell cell = row.createCell(y);
                cell.setCellValue(y);
            }
        }

        /*5.创建输出流(IO流)  03版本文件后缀为:.xls*/
        FileOutputStream fileOutputStream = new FileOutputStream(PATH + "03BIgDate.xls");
        /*6.生成文件*/
        workbook.write(fileOutputStream);
        /*7.关闭流*/
        fileOutputStream.close();

        /*记录程序结束时间*/
        long end = System.currentTimeMillis();

        /*耗时 = 结束时间 - 开始时间 / 1000(毫秒值)*/
        System.out.println("HSSF_03版耗时:" + (double) (end - begin) / 1000);
    }


    /*大量数据写入07版本Excel*/
    @Test
    public void poi07BigDate() throws Exception {
    
    

        /*记录程序开始时间*/
        long begin = System.currentTimeMillis();

        /*1.创建工作簿*/
        Workbook workbook = new XSSFWorkbook();
        //Workbook workbook = new SXSSFWorkbook();
        
        /*2.创建工作表*/
        Sheet sheet = workbook.createSheet("07版本大量数据写入");

        /*x:行 y:列(单元格)*/
        for (int x = 0; x < 65536; x++) {
    
    
            /*3.创建行*/
            Row row = sheet.createRow(x);
            for (int y = 0; y < 10; y++) {
    
    
                /*4.创建列(单元格)*/
                Cell cell = row.createCell(y);
                cell.setCellValue(y);
            }
        }

        /*5.创建输出流(IO流)  07版本文件后缀为:.xlsx*/
        FileOutputStream fileOutputStream = new FileOutputStream(PATH + "07BIgDate.xlsx");
        /*6.生成文件*/
        workbook.write(fileOutputStream);
        /*7.关闭流*/
        fileOutputStream.close();

        /*记录程序结束时间*/
        long end = System.currentTimeMillis();

        /*耗时 = 结束时间 - 开始时间 / 1000(毫秒值)*/
        System.out.println("XSSF_07版耗时:" + (double) (end - begin) / 1000);
    }

03版如果写入超过65536行数据则会出现异常(这就是03版与07版很大的区别,还有就是后缀名不同,03版本是 .xls,07版本是 .xlsx):

在这里插入图片描述

03版HSSF耗时:
优点:过程中写入缓存,不操作磁盘,最后一次性写入磁盘,速度快
缺点:只能操作65536行数据,否则会抛出异常
(java.lang.IllegalArgumentException: Invalid row number (65536) outside allowable range (0…65535))

在这里插入图片描述

07版XSSF耗时:
优点:可以写非常大的数据量,比如几十万
缺点:写数据时非常慢,很耗内存,所有很有可能发生内存溢出(OOM)

在这里插入图片描述

07版SXSSF耗时(07版本将 XSSFWorkbook对象 替换为 SXSSFWorkbook 对象):
优点:在写入庞大数据量时,耗时更少,占用更少的内存
注意:在写入数据时,有一部分会被先写到临时文件,执行完之后需要清理临时文件。如果想自定义内存中的数量可以 new SXSSFWorkbook(传入数量)

在这里插入图片描述
Excel写入总结:

4. POI读取数据 (模拟两个案例)

注:
1. 此案例只是03版本的Excel (如果是07版的Excel 换掉工作簿的对象即可,将HSSFWorkbook 变为XSSFWorkbook)
2. 读取数据最复杂得点在于 转换Excel表中数据。比如日期、数字、小数、字符串、Excel中得函数公式、空单元格
3. 所以可以使用 switch case 对不同类型进行判断 匹配

案例一:

下面有一个Excel表,把其中数据取出来,到控制台输出(都到控制台了,还不能存入数据库吗?):

在这里插入图片描述

    /*读取03版本Excel中多个类型数据*/
    @Test
    public void poi03read() throws Exception {
    
    

        /*获得文件流*/
        FileInputStream FileInputStream = new FileInputStream(PATH + "会员消费商品明细表.xls");

        /*1.创建工作簿*/
        Workbook workbook = new HSSFWorkbook(FileInputStream);

        /*2.得到工作表(一个文件中可能有多个工作表,参数为 索引)*/
        Sheet sheetAt = workbook.getSheetAt(0);

        /*3.获得工作表中所有行*/
        int rowCount = sheetAt.getPhysicalNumberOfRows();

        /*循环所有行*/
        for (int rowNum = 0; rowNum < rowCount; rowNum++) {
    
    
            /*读取行*/
            Row row = sheetAt.getRow(rowNum);
            
            if (row != null) {
    
    
            
                /*4.获得所有列*/
                int cellCount = row.getPhysicalNumberOfCells();
                
                /*循环所有列*/
                for (int cellNum = 0; cellNum < cellCount; cellNum++) {
    
    
                
                    /*获得列(单元格)*/
                    Cell cell = row.getCell(cellNum);
                    
                    /*判断列不为null*/
                    if (cell != null) {
    
    
                        /*获得单元格内容的类型*/
                        int cellType = cell.getCellType();
                        
                        /*内容变量*/
                        String cellValue = "";
                        
                        /*先判断类型,再输出*/
                        switch (cellType) {
    
    
                            /*String类型*/
                            case Cell.CELL_TYPE_STRING:
                                cellValue = cell.getStringCellValue();
                                System.out.print(cellValue + " ");
                                break;
                                
                            /*boolean类型*/
                            case Cell.CELL_TYPE_BOOLEAN:
                                cellValue = String.valueOf(cell.getBooleanCellValue());
                                System.out.print(cellValue + " ");
                                break;
                                
                            /*数字类型(包括日期,数字)*/
                            case Cell.CELL_TYPE_NUMERIC:
                                /*HSSF工具类判断是否为日期*/
                                if (HSSFDateUtil.isCellDateFormatted(cell)) {
    
    
                                    Date date = cell.getDateCellValue();
                                    /*将日期时间转为字符串*/
                                    cellValue = new DateTime(date).toString("yyyy-MM-dd");
                                    System.out.print(cellValue);
                                } else {
    
    
                                    /*不是日期类型 代表是数字,再将它转为字符串*/
                                    cell.setCellType(Cell.CELL_TYPE_STRING);
                                    cellValue = cell.getStringCellValue();
                                    System.out.print(cellValue + " ");
                                }
                                break;
                                
                            /*类型错误*/
                            case Cell.CELL_TYPE_ERROR:
                                break;
                                
                            /*空*/
                            case Cell.CELL_TYPE_BLANK:
                                break;
                        }
                    }
                }
            }
            /*换行*/
            System.out.println();
        }
        /*5.关闭流*/
        FileInputStream.close();
    }

案例二:

下面有一个Excel表,把它读取出来,到控制台输出(获得总和值和单元格中得函数公式):

在这里插入图片描述

    /*读取03版本Excel中的函数公式(包括结果)*/
    @Test
    public void poi03readFormula() throws Exception {
    
    

        /*获得文件流*/
        FileInputStream FileInputStream = new FileInputStream(PATH + "计算公式.xls");

        /*1.创建工作簿*/
        Workbook workbook = new HSSFWorkbook(FileInputStream);

        /*2.得到工作表(一个文件中可能有多个工作表,参数为 索引)*/
        Sheet sheetAt = workbook.getSheetAt(0);

        /*3.获得工作表中所有行*/
        int rowCount = sheetAt.getPhysicalNumberOfRows();

        /*循环所有行*/
        for (int rowNum = 0; rowNum < rowCount; rowNum++) {
    
    
            /*读取行*/
            Row row = sheetAt.getRow(rowNum);
            if (row != null) {
    
    
                /*4.获得所有列*/
                int cellCount = row.getPhysicalNumberOfCells();
                /*循环所有列*/
                for (int cellNum = 0; cellNum < cellCount; cellNum++) {
    
    
                    /*获得列(单元格)*/
                    Cell cell = row.getCell(cellNum);
                    /*判断列不为null*/
                    if (cell != null) {
    
    
                        /*获得单元格内容的类型*/
                        int cellType = cell.getCellType();
                        /*内容变量*/
                        String cellValue = "";
                        /*先判断类型,再输出*/
                        switch (cellType) {
    
    
                            /*函数公式*/
                            case Cell.CELL_TYPE_FORMULA:

                                cell.setCellType(Cell.CELL_TYPE_FORMULA);

                                /*获得函数公式*/
                                String formula = cell.getCellFormula();

                                System.out.println(formula);

                                /*获得函数公式结果*/
                                /*创建*HSSFFormulaEvaluator对象*/
                                FormulaEvaluator formulaEvaluator = new HSSFFormulaEvaluator((HSSFWorkbook) workbook);

                                CellValue evaluate = formulaEvaluator.evaluate(cell);

                                cellValue = evaluate.formatAsString();

                                System.out.println(cellValue);
                                break;
                        }
                    }
                }
            }
        }
        /*5.关闭流*/
        FileInputStream.close();
    }
因为回忆太痛苦,所有我们要一直往前走。

猜你喜欢

转载自blog.csdn.net/weixin_45377770/article/details/108965817