java excel处理-poi

380 阅读2分钟

这是我参与11月更文挑战的第22天,活动详情查看:2021最后一次更文挑战

使用POI

poi会将excel的所有数据放入内存,再将其读出,所以当文件过大时可能会OOM(内存溢出)

适用于小文件,速度快

excel

xls版和xlsx不同

两个版本需要使用不同的依赖

    <!--03版excel-->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.13</version>
        </dependency>
        <!--07版excal-->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.13</version>
        </dependency>

xls

最多只有65536行,使用HSSFWorkbook

写入速度快,但是写入数据的量不大

image.png

public void test1() throws Exception {
       //使用HSSF创建工作簿
       Workbook workbook = new HSSFWorkbook();
//      后缀为xls
       FileOutputStream fileOutputStream = new FileOutputStream(PATH + "studen03.xls");
   }

image.png

xlsx

数量没有限制,使用XSSFWorkbook

写入数据非常慢,耗内存,会发生内存溢出,但是可以写很大的数据量

可以使用加强版的SXSSF

  • 可以写非常大的数据量写速度快占用内存少
  • 会产生临时文件,需要清理
  • 每次读取100条数据,如果超过就被写入临时文件

image.png

public void test2() throws Exception {
       //使用XSSF创建工作簿
       Workbook workbook = new XSSFWorkbook();
    //文件后缀为xlsx
       FileOutputStream fileOutputStream = new FileOutputStream(PATH + "studen07.xlsx");
   }

导出

基本的excel文件生成

public void test2() throws Exception {
       //创建工作簿
       Workbook workbook = new XSSFWorkbook();
        //创建工作表
       Sheet sheet = workbook.createSheet("学生表");
       /*创建行*/
       Row row1 = sheet.createRow(0);
//       第一行的第一个单元格
       Cell cell11 = row1.createCell(0);
       cell11.setCellValue("学号");
//       第一行第二个单元格
       Cell cell12 = row1.createCell(1);
       cell12.setCellValue("名字");
​
       Row row2 = sheet.createRow(1);
       Cell cell21 = row2.createCell(0);
       cell21.setCellValue("1");
       Cell cell22 = row2.createCell(1);
       cell22.setCellValue("yy");
​
​
//      IO流生成文件,xls需要加后缀
       FileOutputStream fileOutputStream = new FileOutputStream(PATH + "studen07.xlsx");
       workbook.write(fileOutputStream);
//       关闭IO流
       fileOutputStream.close();
   }

数据批量

public void test3big() throws Exception {
       long begin = System.currentTimeMillis();
​
       Workbook workbook = new HSSFWorkbook();
       Sheet big = workbook.createSheet("big");
       for (int i = 0; i < 65536; i++) {
           Row row = big.createRow(i);
           for (int j = 0; j < 3; j++) {
               Cell cell = row.createCell(j);
               cell.setCellValue(j);
           }
       }
       System.out.println("over");
       FileOutputStream fileOutputStream = new FileOutputStream(PATH + "03big.xls");
       workbook.write(fileOutputStream);
       fileOutputStream.close();
​
       long last  = System.currentTimeMillis();
       System.out.println("执行时间为"+(last-begin));
   }

HSSF的执行时间

image.png

XSSF时间

image.png

XSSF

Workbook workbook = new SXSSFWorkbook();
//关闭流之后java清理临时文件
        ((SXSSFWorkbook) workbook).dispose();

image.png

导入

 @Test
    public void read03() throws Exception {
        //创建文件流读取文件
        FileInputStream fileOutputStream = new FileInputStream(PATH + "studen03.xls");
        //读取获取到的文件
        Workbook workbook = new HSSFWorkbook(fileOutputStream);
        //读取第一张表
        Sheet sheetAt = workbook.getSheetAt(0);
        //读取第一行
        Row row = sheetAt.getRow(0);
        //读取第一行的第一个单元格
        Cell cell = row.getCell(0);
        System.out.println(cell.getStringCellValue());
​
        fileOutputStream.close();
​
    }

发现如果要获取指定的值,就需要指定他的类型,所以遍历的时候需要判断他的类型

for (Row row : sheetAt){
            for (Cell cell : row){
                //获取值的类型
                int cellType = cell.getCellType();
                    String value = "";
                    switch (cellType){
                        case CELL_TYPE_STRING :
                            value =cell.getStringCellValue();
                            break;
                            //数字里还有日期也要区分
                        case CELL_TYPE_NUMERIC:
                            if(HSSFDateUtil.isCellDateFormatted(cell)){
                                Date date = cell.getDateCellValue();
                                value =date.toString();
                            }
                            else{
                                cell.setCellType(CELL_TYPE_STRING);
                                value = cell.getStringCellValue();
                            }
                            break;
                        case CELL_TYPE_BOOLEAN:
                            value = String.valueOf(cell.getBooleanCellValue()) ;
                            break;
                        case CELL_TYPE_BLANK:
                            break;
                        case CELL_TYPE_ERROR:
                            value = "error";
                            break;
                    }
                System.out.print(value);
            }

导入多个sheet

在导入单个sheet的基础上,将获取指定sheet变成遍历所有sheet

      for(Sheet sheetAt : workbook){
            //获取工作表名称
            System.out.println(sheetAt.getSheetName());