首页 > 其他分享 >2022.10.10 POI

2022.10.10 POI

时间:2022-10-10 15:46:43浏览次数:72  
标签:10 cellNum sheet System cell POI workbook new 2022.10

POI与easyExcel

应用场景

  • 将用户信息导出为excel表格

  • 将Excel表中的信息录入到网站数据库,大大减小网站数据的录入量!

开发中经常会涉及到excel的处理,如导出Excel到数据库中!

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

Apache POI

Apache POI官网: https://poi.apache.org/

 

 

 

 

HSSF 对应 Excel 03 版本,最多支持65535行

XSSF对应 Excel 07 版本,行数无限制

缺点:

  • 使用比较麻烦

  • 数据量大的时候会可能报OOM异常

easyExcel

easyExcel官网地址: https://github.com/alibaba/easyexcel

EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单,节约内存著称。

EasyExcel能大量减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从一个磁盘上一行行读取数据,逐个解析。

下图是EasyExcel和POI在解析Excel时的对比图(时间与空间的相互取舍)。

 

 

官方文档: https://easyexcel.opensource.alibaba.com/

Apache POI

HSSF:Excel97-2003版本,扩展名为.xls。一个sheet最大行数65536,最大列数256。

XSSF:Excel2007版本开始,扩展名为.xlsx。一个sheet最大行数1048576,最大列数16384。

SXSSF:是在XSSF基础上,POI3.8版本开始提供的支持低内存占用的操作方式,扩展名为.xlsx。

1.POI写操作

  1. 创建一个普通空项目empty model,然后新建一个model的maven项目

  2. 引入pom依赖

 <!--导入依赖-->
 <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>
  <!--test-->
  <dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.12</version>
  </dependency>
 </dependencies>

注:03|07版本的写,就是对象不同,方法是一样的

区别:03版最多65536行,07行数没有限制 ,03 HSSFWorkbook() 后缀xls,07 XSSFWorkbook() 后缀xlsx,

 

 

excel中的对象

  • 工作薄

  • 工作表

  • 单元格

03版本

 package com.xing;
 ​
 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.joda.time.DateTime;
 import org.junit.Test;
 ​
 import java.io.FileOutputStream;
 import java.io.IOException;
 ​
 public class ExcelWriteTest {
 
     String PATH="C:\\Users\\16159\\Desktop\\新建文件夹\\";
 
     @Test
     public void testWrite03() throws IOException {
         //1,创建一个工作簿
         Workbook workbook = new HSSFWorkbook();
         //创建一个工作表 通过工作簿创建工作表
         Sheet sheet = workbook.createSheet("03统计表");
 ​
         //2,创建一行(1,1) 0代表第一行
         Row row1 = sheet.createRow(0);
         //创建一个单元格 通过行创建   0代表row1行的第一个单元格
         Cell cell11 = row1.createCell(0);
 ​
         //在(1,1)中写入数据
         cell11.setCellValue("新增观众");
 ​
         //(1,2)
         Cell cell12 = row1.createCell(1);
         //在(1,2)中写入数据
         cell12.setCellValue(666);
 ​
         //第二行(2,1)
         Row row2 = sheet.createRow(1);
         Cell cell21 = row2.createCell(0);
         cell21.setCellValue("时间记录");
 ​
         //(2,2)
         Cell cell22 = row2.createCell(1);
         cell22.setCellValue(new DateTime().toString("yyyy-MM-dd HH:mm:ss"));
 
         //生成一张表(IO流)03版本使用xls结尾!
         FileOutputStream fileOutputStream = new FileOutputStream(PATH + "03版本测试.xls");
         //工作簿输出
         workbook.write(fileOutputStream);
 
         //关闭流
         fileOutputStream.close();
 
         System.out.println("03生成成功");
 
    }
 }

运行结果

 

 

07

 @Test
 public void testWrite07() throws IOException {
     //1,创建一个工作簿
     Workbook workbook = new XSSFWorkbook();
     //创建一个工作表 通过工作簿创建工作表
     Sheet sheet = workbook.createSheet("03统计表");
 ​
     //2,创建一行(1,1) 0代表第一行
     Row row1 = sheet.createRow(0);
     //创建一个单元格 通过行创建   0代表row1行的第一个单元格
     Cell cell11 = row1.createCell(0);
 ​
     //在(1,1)中写入数据
     cell11.setCellValue("新增观众");
 ​
     //(1,2)
     Cell cell12 = row1.createCell(1);
     //在(1,2)中写入数据
     cell12.setCellValue(666);
 ​
     //第二行(2,1)
     Row row2 = sheet.createRow(1);
     Cell cell21 = row2.createCell(0);
     cell21.setCellValue("时间记录");
 ​
     //(2,2)
     Cell cell22 = row2.createCell(1);
     cell22.setCellValue(new DateTime().toString("yyyy-MM-dd HH:mm:ss"));
 ​
     //生成一张表(IO流)03版本使用xlsx结尾!
     FileOutputStream fileOutputStream = new FileOutputStream(PATH + "07版本测试.xlsx");
     //工作簿输出
     workbook.write(fileOutputStream);
 ​
     //关闭流
     fileOutputStream.close();
 ​
     System.out.println("07生成成功");
 ​
 }

07和03不同的就这两处:注意对象的一个区别,文件后缀!

 //03
 Workbook workbook = new HSSFWorkbook();
 ​
 //07版本
 Workbook workbook = new XSSFWorkbook();
 ​
 //加快开发07版本
 Workbook workbook = new SXSSFWorkbook();
 
 //生成一张表(IO流)07版本使用xlsx结尾!注意文件后缀名
 FileOutputStream fos = new FileOutputStream(PATH+"07版本Excel测试.xlsx");

03版:

注:大文件写用HSSF

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

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

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

     @Test
     public void testwrite03BigData() throws IOException {
         //时间
         long begin = System.currentTimeMillis();
 ​
         //创建一个薄
         Workbook workbook = new HSSFWorkbook();
         //创建表
         Sheet sheet = workbook.createSheet();
 ​
         // 行
         for (int rowNum = 0; rowNum < 65536; rowNum++) {
             Row row = sheet.createRow(rowNum);
             //列
             for (int cellNum = 0; cellNum < 10; cellNum++) {
                 Cell cell = row.createCell(cellNum);
                 //写入数据
                 cell.setCellValue(cellNum);
            }
        }
         FileOutputStream fos = new FileOutputStream(PATH + "03版本Excel大量数据测试.xls");
         workbook.write(fos);
         fos.close();
         System.out.println("over");
 ​
         long end = System.currentTimeMillis();
         // 运行时间
         System.out.println((double) (end - begin) / 1000);
    }

07版本:

大文件写用XSSF

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

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

 @Test
     public void testwrite07BigData() throws IOException {
         //时间
         long begin = System.currentTimeMillis();
 ​
         //创建一个薄
         Workbook workbook = new XSSFWorkbook();
         //创建表
         Sheet sheet = workbook.createSheet();
 ​
         // 行
         for (int rowNum = 0; rowNum < 100000; rowNum++) {
             Row row = sheet.createRow(rowNum);
             //列
             for (int cellNum = 0; cellNum < 10; cellNum++) {
                 Cell cell = row.createCell(cellNum);
                 //写入数据
                 cell.setCellValue(cellNum);
            }
        }
         FileOutputStream fos = new FileOutputStream(PATH + "07版本Excel大量数据测试.xlsx");
         workbook.write(fos);
         fos.close();
         System.out.println("over");
 ​
         long end = System.currentTimeMillis();
         System.out.println((double) (end - begin) / 1000);
    }
 ​

大文件写用SXSSF

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

注意:

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

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

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

SXSSWorkbook 来自官方解释:实现:BigGridDemo策略的流式XSSFWorkbook版本。这允许写入非常大的文件而不会耗尽内存,因为任何时候只有可配置的行部分被保存在内存中。

读取07及以上版本的excel仍然是“XSSFWorkbook”,写入则为“SXSSFWorkbook ”。后缀和07一样是.xlsx。

最后调用workbook.dispose()删除临时文件。

     @Test
     public void testwrite07BigDataS() throws IOException {
         //时间
         long begin = System.currentTimeMillis();
 ​
         //创建一个薄
         Workbook workbook = new SXSSFWorkbook();
         //创建表
         Sheet sheet = workbook.createSheet();
 ​
         // 行
         for (int rowNum = 0; rowNum < 100000; rowNum++) {
             Row row = sheet.createRow(rowNum);
             //列
             for (int cellNum = 0; cellNum < 10; cellNum++) {
                 Cell cell = row.createCell(cellNum);
                 //写入数据
                 cell.setCellValue(cellNum);
            }
        }
         FileOutputStream fos = new FileOutputStream(PATH + "07升级版本Excel大量数据测试.xlsx");
         workbook.write(fos);
         fos.close();
 ​
         //清除临时缓存
        ((SXSSFWorkbook)workbook).dispose();
 ​
         System.out.println("over");
         long end = System.currentTimeMillis();
         System.out.println((double) (end - begin) / 1000);
    }

请注意,仍然可能会消耗大量内存,这些内存基于您正在使用的功能,例如合并区域,注释..…...仍然只存储在内存中,因此如果广泛使用,可能需要大量内存。

2.POI-Excel读

03类型

 package com.xing;
 ​
 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.junit.Test;
 
 import java.io.FileInputStream;
 
 public class ExcelReadTest {
 ​
     String PATH="C:\\Users\\16159\\Desktop\\新建文件夹\\";
 ​
 ​
     @Test
     public void testRead03() throws Exception {
         //获取文件流
         FileInputStream fis = new FileInputStream(PATH + "03版本测试.xls");
         //1、读取一个工作簿。使用 exceL能操作的这边他都可以操作!
         Workbook workbook = new HSSFWorkbook(fis);
         //2、得到表 得到第0个表
         Sheet sheet = workbook.getSheetAt(0);
         //3、得到行
         Row row = sheet.getRow(0);
         //4、得到列
         Cell cell = row.getCell(0);
 ​
         // cell.getNumericCellValue(); 得到值
 ​
         //读取值的时候,一定要注意类型! 否则读取失败
         //getStringCellValue 获取字符串类型 getNumericCellValue获取数值类型
         System.out.println(cell.getNumericCellValue());
         fis.close();
    }
 }

07类型

     @Test
     public void testRead07() throws Exception {
         //获取文件流
         FileInputStream fis = new FileInputStream(PATH + "07版本测试.xlsx");
         //1、读取一个工作簿。使用 exceL能操作的这边他都可以操作!
         Workbook workbook = new XSSFWorkbook(fis);
         //2、得到表 得到第0个表
         Sheet sheet = workbook.getSheetAt(0);
         //3、得到行
         Row row = sheet.getRow(0);
         //4、得到列
         Cell cell = row.getCell(0);
 ​
         // cell.getNumericCellValue(); 得到值
 ​
         //读取值的时候,一定要注意类型! 否则读取失败
         //getStringCellValue 获取字符串类型 getNumericCellValue获取数值类型
         System.out.println(cell.getNumericCellValue());
         fis.close();
    }

注:获取值的类型即可,读取不同的数据类型

 @Test
 public void testCellType() throws Exception {
 ​
     //获取文件流
     FileInputStream fis = new FileInputStream(PATH +"课题信息表20190701.xlsx");
 ​
     //读取一个工作簿。使用 excel能操作的这边他都可以操作
     Workbook workbook = new XSSFWorkbook(fis);
     //读取第一个工作表
     Sheet sheet = workbook.getSheetAt(0);
 ​
     //获取第一行
     Row rowTitle = sheet.getRow(0);
     if (rowTitle != null) {
         //得到一行有多少列有数据
         int cellCount = rowTitle.getPhysicalNumberOfCells();
         // 遍历改行的每一列
         for (int cellNum = 0; cellNum < cellCount; cellNum++) {
             //获取改行的某一个单元格
             Cell cell = rowTitle.getCell(cellNum);
             if (cell != null) {
                 //将该单元格以字符串类型输出
                 String cellValue = cell.getStringCellValue();
                 System.out.print(cellValue + "|");
            }
        }
         System.out.println();
    }
 ​
     //获取表中的内容
     //获取表中有多少行有数据
     int rowCount = sheet.getPhysicalNumberOfRows();
     for (int rowNum = 1; rowNum < rowCount; rowNum++) {
         //获取每一行
         Row rowData = sheet.getRow(rowNum);
         if (rowData != null) {
             //读取改行对应的列数
             int cellCount = rowTitle.getPhysicalNumberOfCells();
             //遍历改行的单元格
             for (int cellNum = 0; cellNum < cellCount; cellNum++) {
                 //获取单元格数据(但是没有赋予类型)
                 Cell cell = rowData.getCell(cellNum);
                 //匹配列的数据类型
                 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_BOOLEAN://布尔
                             System.out.print("【 BOOLEAN】");
                             cellValue = String.valueOf(cell.getBooleanCellValue());
                             break;
                         case HSSFCell.CELL_TYPE_BLANK://空
                             System.out.print("【 BLANK】");
                             break;
                         case HSSFCell.CELL_TYPE_NUMERIC://数字(日期、普通数字)
                             System.out.print("【 NUMERIC】");
                             //判断当前单元格是不是时间类型
                             if (HSSFDateUtil.isCellDateFormatted(cell)) {// 日期
                                 System.out.print("--【日期】");
                                 Date date = cell.getDateCellValue();
                                 cellValue = new DateTime(date).toString("yyyy-MM-dd");
                            } else {
                                 //不是日期格式,防止数字过长!
                                 System.out.print("--【转换为字符串输出】");
                                 // cellValue = cell.getNumericCellValue();
                                 // 转换为字符串
                                 cell.setCellType(HSSFCell.CELL_TYPE_STRING);
                                 cellValue = cell.toString();
                            }
                             break;
                         case HSSFCell.CELL_TYPE_ERROR://错误
                             System.out.print("【 数据类型错误】");
                             break;
                    }
                     System.out.println(cellValue);
                }
            }
        }
    }
     //关闭流
     fis.close();
 }
 ​

计算公式(了解)

 @Test
     public void testFormula() throws Exception {
         FileInputStream fis = new FileInputStream(PATH+"公式.xls");
         //创建一个工作簿。使用 excel能操作的这边他都可以操作
         Workbook workbook = new HSSFWorkbook(fis);
         Sheet sheet = workbook.getSheetAt(0);
 ​
         //确定单元格位置
         Row row = sheet.getRow(4);
         Cell cell = row.getCell(0);
 ​
         //计算公式 evaL
         FormulaEvaluator FormulaEvaluator = new HSSFFormulaEvaluator((HSSFWorkbook) workbook);
 ​
         //输出单元格的内容
         int cellType = cell.getCellType();
         switch (cellType) {
             case Cell.CELL_TYPE_FORMULA://公式
                 //获取该单元格的计算公式
                 String formula = cell.getCellFormula();
                 System.out.println(formula);//=SUM(A2:A4)
 ​
                 //计算该单元格的值
                 CellValue evaluate = FormulaEvaluator.evaluate(cell);
                 //将值格式化为字符串
                 String cellValue = evaluate.formatAsString();
                 System.out.println(cellValue);
                 break;
        }
    }

运行结果

 SUM(A2:A4)
 600.0

 

标签:10,cellNum,sheet,System,cell,POI,workbook,new,2022.10
From: https://www.cnblogs.com/shanzha/p/16775947.html

相关文章