2021-06-22

010_POI和EasyExcel

目录
  • 常用场景
  • 流行技术:Apache POI和EasyExcel
  • Apache POI简介
  • EasyExcel简介
  • JAVA解析Excel工具EasyExcel
    • 64M内存1分钟内读取75M(46W行25列)的Excel
    • Excel读写时候内存溢出
    • 其他开源框架使用复杂
    • 其他开源框架存在一些BUG修复不及时
    • Excel格式分析格式分析
    • 核心原理
      • 解压文件读取通过文件形式
      • 避免将全部数据一次加载到内存
      • 抛弃不重要的数据
  • POI-Excel基本写
    • 创建空项目
    • 创建子模块qing-poi
    • 导入依赖
    • Excel的对象
      • 工作簿
      • 工作表
      • 单元格
    • 写03版Excel
    • 写07版Excel
    • 03和07版的不同
  • POI-Excel大文件写
    • HSSF写大文件(03)
    • XSSF写大文件(07)
    • SXSSF写大文件(07快速版)
  • POI-Excel基本读
    • 读03版Excel
    • 读07版Excel
    • 读取不同的数据类型
      • 自己处理不同的数据类型
      • 使用cell.toString处理不同的数据类型,但会有日期和长数字会显示问题
      • 使用cell.toString处理不同的数据类型,自己处理数字和日期显示
    • 读取公式及计算
  • EasyExcel使用image.png
    • 打开github,找到pom.
    • 复制EasyExcel依赖到本地pom.
    • 测试简单的写
      • 写实体
      • 导入lombok依赖
      • 写出文件
    • 测试简单的读
      • 写监听器
      • 读取文件


常用场景

  1. 将数据导出为Excel表格
  2. 将Excel表中的数据录入到网站数据库

流行技术:Apache POI和EasyExcel

Apache POI简介

image.png

EasyExcel简介

EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。github地址:https://github.com/alibaba/easyexcel

JAVA解析Excel工具EasyExcel

Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到几M,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便

64M内存1分钟内读取75M(46W行25列)的Excel

当然还有急速模式能更快,但是内存占用会在100M多一点
关于EasyExcel

Excel读写时候内存溢出

虽然POI是目前使用最多的用来做excel解析的框架,但这个框架并不那么完美。大部分使用POI都是使用他的userModel模式。userModel的好处是上手容易使用简单,随便拷贝个代码跑一下,剩下就是写业务转换了,虽然转换也要写上百行代码,相对比较好理解。然而userModel模式最大的问题是在于非常大的内存消耗,一个几兆的文件解析要用掉上百兆的内存。现在很多应用采用这种模式,之所以还正常在跑一定是并发不大,并发上来后一定会OOM或者频繁的full gc。

其他开源框架使用复杂

对POI有过深入了解的估计才知道原来POI还有SAX模式。但SAX模式相对比较复杂,excel有03和07两种版本,两个版本数据存储方式截然不同,sax解析方式也各不一样。想要了解清楚这两种解析方式,才去写代码测试,估计两天时间是需要的。再加上即使解析完,要转换到自己业务模型还要很多繁琐的代码。总体下来感觉至少需要三天,由于代码复杂,后续维护成本巨大。

其他开源框架存在一些BUG修复不及时

由于我们的系统大多数都是大并发的情况下运行的,在大并发情况下,我们会发现poi存在一些bug,如果让POI团队修复估计遥遥无期了。所以我们在easyexcel对这些bug做了规避。

Excel格式分析格式分析

  • xls是Microsoft Excel2007前excel的文件存储格式,实现原理是基于微软的ole db是微软com组件的一种实现,本质上也是一个微型数据库,由于微软的东西很多不开源,另外也已经被淘汰,了解它的细节意义不大,底层的编程都是基于微软的com组件去开发的。
  • xlsx是Microsoft Excel2007后excel的文件存储格式,实现是基于open
  • csv 我们可以理解为纯文本文件,可以被excel打开。他的格式非常简单,解析起来和解析文本文件一样。

核心原理

写有大量数据的xlsx文件时,POI为我们提供了SXSSFWorkBook类来处理,这个类的处理机制是当内存中的数据条数达到一个极限数量的时候就flush这部分数据,再依次处理余下的数据,这个在大多数场景能够满足需求。
读有大量数据的文件时,使用WorkBook处理就不行了,因为POI对文件是先将文件中的cell读入内存,生成一个树的结构(针对Excel中的每个sheet,使用TreeMap存储sheet中的行)。如果数据量比较大,则同样会产生java.lang.OutOfMemoryError: Java heap space错误。POI官方推荐使用"XSSF and SAX(event API)"方式来解决。
分析清楚POI后要解决OOM有3个关键。

解压文件读取通过文件形式


避免将全部数据一次加载到内存

采用sax模式一行一行解析,并将一行的解析结果以观察者的模式通知处理。

抛弃不重要的数据

Excel解析时候会包含样式,字体,宽度等数据,但这些数据是我们不关心的,如果将这部分数据抛弃可以大大降低内存使用。Excel中数据如下Style占了相当大的空间。

POI-Excel基本写

创建空项目

image.png

创建子模块qing-poi

image.png
image.png

导入依赖

<?

Excel的对象

image.png

工作簿

工作表

单元格

写03版Excel

package com.qing;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.jupiter.api.Test;import java.io.FileOutputStream;import java.io.IOException;public class ExcelWriteTest { // 路径 String PATH = "D:\\code\\excel\\qing-poi\\"; /**  * 写03版Excel  */ @Test public void testWrite03() throws IOException {  // 1.创建一个工作簿,03版使用对象HSSFWorkbook,07版使用对象XSSFWorkbook  Workbook workbook = new HSSFWorkbook();  // 2.创建一个工作表,不传参默认Sheet1  Sheet sheet = workbook.createSheet("自定义Sheet1");  // 3.创建一个行,0表示第一行  Row row1 = sheet.createRow(0);  // 4.创建一个单元格,0表示第一列的单元格  // 第一行  // (1,1)  Cell cell11 = row1.createCell(0);  cell11.setCellValue("第一行第一列");  // (1,2)  Cell cell12 = row1.createCell(1);  cell12.setCellValue("第一行第二列");  // 第二行  Row row2 = sheet.createRow(1);  // (2,1)  Cell cell21 = row2.createCell(0);  cell21.setCellValue("第二行第一列");  // (2,2)  Cell cell22 = row2.createCell(1);  cell22.setCellValue("第二行第二列");  // 第三行  Row row3 = sheet.createRow(2);  // (3,1)  Cell cell31 = row3.createCell(0);  cell31.setCellValue("时间");  // (2,2)  Cell cell32 = row3.createCell(1);  // joda的日期比较好用  String time = new DateTime().toString("yyyy-MM-dd HH:mm:ss");  cell32.setCellValue(time);  // 5.生成一张表(IO流) 03版本必须使用xls结尾  FileOutputStream fileOutputStream = new FileOutputStream(PATH + "03.xls");  // 输出  workbook.write(fileOutputStream);  // 6.关闭流  fileOutputStream.close();  System.out.println("03.xls生成完毕"); }}

写07版Excel

package com.qing;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.joda.time.DateTime;import org.junit.jupiter.api.Test;import java.io.FileOutputStream;import java.io.IOException;public class ExcelWriteTest { // 路径 String PATH = "D:\\code\\excel\\qing-poi\\"; /**  * 写07版Excel  */ @Test public void testWrite07() throws IOException {  // 1.创建一个工作簿,03版使用对象HSSFWorkbook,07版使用对象XSSFWorkbook  Workbook workbook = new XSSFWorkbook();  // 2.创建一个工作表,不传参默认Sheet1  Sheet sheet = workbook.createSheet("自定义Sheet1");  // 3.创建一个行,0表示第一行  Row row1 = sheet.createRow(0);  // 4.创建一个单元格,0表示第一列的单元格  // 第一行  // (1,1)  Cell cell11 = row1.createCell(0);  cell11.setCellValue("第一行第一列");  // (1,2)  Cell cell12 = row1.createCell(1);  cell12.setCellValue("第一行第二列");  // 第二行  Row row2 = sheet.createRow(1);  // (2,1)  Cell cell21 = row2.createCell(0);  cell21.setCellValue("第二行第一列");  // (2,2)  Cell cell22 = row2.createCell(1);  cell22.setCellValue("第二行第二列");  // 第三行  Row row3 = sheet.createRow(2);  // (3,1)  Cell cell31 = row3.createCell(0);  cell31.setCellValue("时间");  // (2,2)  Cell cell32 = row3.createCell(1);  // joda的日期比较好用  String time = new DateTime().toString("yyyy-MM-dd HH:mm:ss");  cell32.setCellValue(time);  // 5.生成一张表(IO流) 07版本必须使用xlsx结尾  FileOutputStream fileOutputStream = new FileOutputStream(PATH + "07.xlsx");  // 输出  workbook.write(fileOutputStream);  // 6.关闭流  fileOutputStream.close();  System.out.println("07.xlsx生成完毕"); }}

03和07版的不同

  1. 2003版本和2007版本存在兼容性的问题
  2. 03版最多只有65536行
  3. 03和07版本的写,就是对象不同,方法是一样的
  4. 后缀不同,03使用xls,07使用xlsx

POI-Excel大文件写

HSSF写大文件(03)

  • 优点
    • 过程中写入缓存,不操作磁盘,最后一次性写入磁盘,速度快
  • 缺点
    • 最多只能处理65536行,否则会抛出异常
java.lang.IllegalArgumentException: Invalid row number (65536) outside allowable range (0..65535)
package com.qing;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.joda.time.DateTime;import org.junit.jupiter.api.Test;import java.io.FileOutputStream;import java.io.IOException;public class ExcelWriteTest { // 路径 String PATH = "D:\\code\\excel\\qing-poi\\"; /**  * 写03版Excel-大文件  */ @Test public void testWrite03BigData() throws IOException {  // 起始时间  long begin = System.currentTimeMillis();  // 1.创建一个工作簿,03版使用对象HSSFWorkbook,07版使用对象XSSFWorkbook  Workbook workbook = new HSSFWorkbook();  // 2.创建一个工作表,不传参默认Sheet1  Sheet sheet = workbook.createSheet("自定义Sheet1");  // 3.写入数据  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);   }  }  // 4.生成一张表(IO流) 03版本必须使用xls结尾  FileOutputStream fileOutputStream = new FileOutputStream(PATH + "03BigData.xls");  // 输出  workbook.write(fileOutputStream);  // 5.关闭流  fileOutputStream.close();  System.out.println("03BigData.xls生成完毕");  // 截止时间  long end = System.currentTimeMillis();  System.out.println("消耗时间:" + ((double)end-begin)/1000 + "s"); }}

image.png

XSSF写大文件(07)

  • 优点
    • 可以写较大的数据量,如:20万条
  • 缺点
    • 写数据时速度非常慢,非常耗内存,也会发生内存溢出,如:100万条、1000万条
package com.qing;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.joda.time.DateTime;import org.junit.jupiter.api.Test;import java.io.FileOutputStream;import java.io.IOException;public class ExcelWriteTest { // 路径 String PATH = "D:\\code\\excel\\qing-poi\\"; /**  * 写07版Excel-大文件  */ @Test public void testWrite07BigData() throws IOException {  // 起始时间  long begin = System.currentTimeMillis();  // 1.创建一个工作簿,03版使用对象HSSFWorkbook,07版使用对象XSSFWorkbook  Workbook workbook = new XSSFWorkbook();  // 2.创建一个工作表,不传参默认Sheet1  Sheet sheet = workbook.createSheet("自定义Sheet1");  // 3.写入数据  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);   }  }  // 4.生成一张表(IO流) 07版本必须使用xlsx结尾  FileOutputStream fileOutputStream = new FileOutputStream(PATH + "07BigData.xlsx");  // 输出  workbook.write(fileOutputStream);  // 5.关闭流  fileOutputStream.close();  System.out.println("07BigData.xlsx生成完毕");  // 截止时间  long end = System.currentTimeMillis();  System.out.println("消耗时间:" + ((double)end-begin)/1000 + "s"); }}

image.png

SXSSF写大文件(07快速版)

  • 优点
    • 可以写非常大的数据量,如:100万条甚至更多条
    • 写数据速度快,占用更少的内存
  • 缺点
  • 注意
    • 过程中会产生临时文件,需要清理临时文件((SXSSFWorkbook) workbook).dispose();
    • 默认由100条记录被保存在内存中,如果超过该数量,则最前面的数据被写入临时文件
    • 如果想自定义内存中数据的数量,可以使用new SXSSFWorkbook(数量);

image.png

package com.qing;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.streaming.SXSSFWorkbook;import org.apache.poi.xssf.usermodel.XSSFWorkbook;import org.joda.time.DateTime;import org.junit.jupiter.api.Test;import java.io.FileOutputStream;import java.io.IOException;public class ExcelWriteTest { // 路径 String PATH = "D:\\code\\excel\\qing-poi\\"; /**  * 写07版Excel-大文件(SXSSF快速版)  */ @Test public void testWrite07BigDataS() throws IOException {  // 起始时间  long begin = System.currentTimeMillis();  // 1.创建一个工作簿,03版使用对象HSSFWorkbook,07版使用对象XSSFWorkbook,07快速版使用对象SXSSFWorkbook  Workbook workbook = new SXSSFWorkbook();  // 2.创建一个工作表,不传参默认Sheet1  Sheet sheet = workbook.createSheet("自定义Sheet1");  // 3.写入数据  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);   }  }  // 4.生成一张表(IO流) 07版本必须使用xlsx结尾  FileOutputStream fileOutputStream = new FileOutputStream(PATH + "07BigDataS.xlsx");  // 输出  workbook.write(fileOutputStream);  // 5.关闭流  fileOutputStream.close();  // 清除临时文件  ((SXSSFWorkbook) workbook).dispose();  System.out.println("07BigDataS.xlsx生成完毕");  // 截止时间  long end = System.currentTimeMillis();  System.out.println("消耗时间:" + ((double)end-begin)/1000 + "s"); }}

image.png

POI-Excel基本读

读03版Excel

package com.qing;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.jupiter.api.Test;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;public class ExcelReadTest { // 路径 String PATH = "D:\\code\\excel\\qing-poi\\"; /**  * 读03版Excel  */ @Test public void testRead03() throws IOException {  // 1.获取文件流  FileInputStream fileInputStream = new FileInputStream(PATH + "03.xls");  // 2.创建一个工作簿  Workbook workbook = new HSSFWorkbook(fileInputStream);  // 3.得到表,可以通过名称或下标获取  Sheet sheet = workbook.getSheetAt(0);  // 4.得到行  Row row = sheet.getRow(0);  // 5.得到单元格  Cell cell = row.getCell(0);  // 6.读取值,读取值的时候要注意数据类型,否则会报错//  System.out.println(cell.getNumericCellValue());  System.out.println(cell.getStringCellValue());  // 7.关闭流  fileInputStream.close(); }}

image.png

读07版Excel

package com.qing;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.jupiter.api.Test;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;public class ExcelReadTest { // 路径 String PATH = "D:\\code\\excel\\qing-poi\\"; /**  * 读07版Excel  */ @Test public void testRead07() throws IOException {  // 1.获取文件流  FileInputStream fileInputStream = new FileInputStream(PATH + "07.xlsx");  // 2.创建一个工作簿  Workbook workbook = new XSSFWorkbook(fileInputStream);  // 3.得到表,可以通过名称或下标获取  Sheet sheet = workbook.getSheetAt(0);  // 4.得到行  Row row = sheet.getRow(0);  // 5.得到单元格  Cell cell = row.getCell(0);  // 6.读取值,读取值的时候要注意数据类型,否则会报错//  System.out.println(cell.getNumericCellValue());  System.out.println(cell.getStringCellValue());  // 7.关闭流  fileInputStream.close(); }}

image.png

读取不同的数据类型

image.png

自己处理不同的数据类型

package com.qing;import org.apache.poi.hssf.usermodel.HSSFDateUtil;import org.apache.poi.hssf.usermodel.HSSFWorkbook;import org.apache.poi.ss.usermodel.*;import org.apache.poi.xssf.usermodel.XSSFWorkbook;import org.joda.time.DateTime;import org.junit.jupiter.api.Test;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.util.Date;public class ExcelReadTest { // 路径 String PATH = "D:\\code\\excel\\qing-poi\\"; /**  * 读取不同的数据类型  */ @Test public void testCellType() throws IOException {  // 1.获取文件流  FileInputStream fileInputStream = new FileInputStream(PATH + "明细表.xls");  // 2.创建一个工作簿  Workbook workbook = new HSSFWorkbook(fileInputStream);  // 3.得到表,可以通过名称或下标获取  Sheet sheet = workbook.getSheetAt(0);  // 4.获取表头行内容  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) {     // 获取值类型     CellType cellType = cell.getCellType();     // 知道表头行都是字符串,所以不需要根据类型输出     String cellValue = cell.getStringCellValue();     System.out.print(cellValue + " | ");    }   }  }  // 5.获取表体行内容  // 获取行数  int rowCount = sheet.getPhysicalNumberOfRows();  // 跳过表头行,所有从1开始  for (int rowNum = 1; rowNum < rowCount; rowNum++) {   System.out.println();   Row row = sheet.getRow(rowNum);   if (row != null) {    // 获取表头行列数    int cellCount = rowTitle.getPhysicalNumberOfCells();    for (int cellNum = 0; cellNum < cellCount; cellNum++) {     System.out.print("[" + (rowNum+1) + "-" + (cellNum+1) + "]");     Cell cell = row.getCell(cellNum);     if (cell != null) {      // 获取值类型      CellType cellType = cell.getCellType();      String cellValue = "";      // 匹配数据类型      switch (cellType) {       case _NONE: // 未知类型,仅限内部使用        System.out.print("[未知类型]");        break;       case NUMERIC: // 数字类型(日期、普通数字)        System.out.print("[数字类型(日期、普通数字)]");        if (DateUtil.isCellDateFormatted(cell)) { // 日期         System.out.print("[日期]");         Date date = cell.getDateCellValue();         cellValue = new DateTime(date).toString("yyyy-MM-dd");        } else {         // 不是日期格式,防止数字过长,转换为字符串输出         System.out.print("[数字]");         cell.setCellType(CellType.STRING);         cellValue = cell.toString();        }        break;       case STRING: // 字符串        System.out.print("[字符串]");        cellValue = cell.getStringCellValue();        break;       case FORMULA: // 公式        System.out.print("[公式]");                // 获取公式计算程序        FormulaEvaluator formulaEvaluator = new HSSFFormulaEvaluator((HSSFWorkbook) workbook);        // 计算公式        CellValue evaluate = formulaEvaluator.evaluate(cell);        cellValue = evaluate.formatAsString();        break;       case BLANK: // 空单元格,没值,但有单元格样式        System.out.print("[空]");        break;       case BOOLEAN: // 布尔值        System.out.print("[布尔值]");        cellValue = String.valueOf(cell.getBooleanCellValue());        break;       case ERROR: // 错误单元格        System.out.print("[错误单元格]");        break;      }      System.out.println(cellValue);     }    }   }  }  // 7.关闭流  fileInputStream.close(); }}

image.png

使用cell.toString处理不同的数据类型,但会有日期和长数字会显示问题

package com.qing;import org.apache.poi.hssf.usermodel.HSSFDateUtil;import org.apache.poi.hssf.usermodel.HSSFWorkbook;import org.apache.poi.ss.usermodel.*;import org.apache.poi.xssf.usermodel.XSSFWorkbook;import org.joda.time.DateTime;import org.junit.jupiter.api.Test;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.util.Date;public class ExcelReadTest { // 路径 String PATH = "D:\\code\\excel\\qing-poi\\"; /**  * 读取不同的数据类型-使用cell.toString()  */ @Test public void testCellTypeCellToString() throws IOException {  // 1.获取文件流  FileInputStream fileInputStream = new FileInputStream(PATH + "明细表.xls");  // 2.创建一个工作簿  Workbook workbook = new HSSFWorkbook(fileInputStream);  // 3.得到表,可以通过名称或下标获取  Sheet sheet = workbook.getSheetAt(0);  // 4.获取表头行内容  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) {     // 获取值类型     CellType cellType = cell.getCellType();     // 知道表头行都是字符串,所以不需要根据类型输出     String cellValue = cell.getStringCellValue();     System.out.print(cellValue + " | ");    }   }  }  // 5.获取表体行内容  // 获取行数  int rowCount = sheet.getPhysicalNumberOfRows();  // 跳过表头行,所有从1开始  for (int rowNum = 1; rowNum < rowCount; rowNum++) {   System.out.println();   Row row = sheet.getRow(rowNum);   if (row != null) {    // 获取表头行列数    int cellCount = rowTitle.getPhysicalNumberOfCells();    for (int cellNum = 0; cellNum < cellCount; cellNum++) {     System.out.print("[" + (rowNum+1) + "-" + (cellNum+1) + "]");     Cell cell = row.getCell(cellNum);     if (cell != null) {      // 获取值类型      CellType cellType = cell.getCellType();      System.out.print("[" + cellType + "]");      String cellValue = cell.toString();      System.out.println(cellValue);     }    }   }  }  // 7.关闭流  fileInputStream.close(); }}

image.png

使用cell.toString处理不同的数据类型,自己处理数字和日期显示

package com.qing;import org.apache.poi.hssf.usermodel.HSSFDateUtil;import org.apache.poi.hssf.usermodel.HSSFWorkbook;import org.apache.poi.ss.usermodel.*;import org.apache.poi.xssf.usermodel.XSSFWorkbook;import org.joda.time.DateTime;import org.junit.jupiter.api.Test;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.util.Date;public class ExcelReadTest { // 路径 String PATH = "D:\\code\\excel\\qing-poi\\"; /**  * 读取不同的数据类型-使用cell.toString()-优化日期和数字的显示  */ @Test public void testCellTypeCellToStringNumeric() throws IOException {  // 1.获取文件流  FileInputStream fileInputStream = new FileInputStream(PATH + "明细表.xls");  // 2.创建一个工作簿  Workbook workbook = new HSSFWorkbook(fileInputStream);  // 3.得到表,可以通过名称或下标获取  Sheet sheet = workbook.getSheetAt(0);  // 4.获取表头行内容  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) {     // 获取值类型     CellType cellType = cell.getCellType();     // 知道表头行都是字符串,所以不需要根据类型输出     String cellValue = cell.getStringCellValue();     System.out.print(cellValue + " | ");    }   }  }  // 5.获取表体行内容  // 获取行数  int rowCount = sheet.getPhysicalNumberOfRows();  // 跳过表头行,所有从1开始  for (int rowNum = 1; rowNum < rowCount; rowNum++) {   System.out.println();   Row row = sheet.getRow(rowNum);   if (row != null) {    // 获取表头行列数    int cellCount = rowTitle.getPhysicalNumberOfCells();    for (int cellNum = 0; cellNum < cellCount; cellNum++) {     System.out.print("[" + (rowNum+1) + "-" + (cellNum+1) + "]");     Cell cell = row.getCell(cellNum);     if (cell != null) {      // 获取值类型      CellType cellType = cell.getCellType();      System.out.print("[" + cellType + "]");      String cellValue = "";      // 匹配数据类型      switch (cellType) {       case NUMERIC: // 数字类型(日期、普通数字)        System.out.print("[数字类型(日期、普通数字)]");        if (DateUtil.isCellDateFormatted(cell)) { // 日期         Date date = cell.getDateCellValue();         cellValue = new DateTime(date).toString("yyyy-MM-dd");    ......

原文转载:http://www.shaoqun.com/a/819667.html

跨境电商:https://www.ikjzd.com/

深诺互动:https://www.ikjzd.com/w/2746

一淘网比价平台:https://www.ikjzd.com/w/1698

beien:https://www.ikjzd.com/w/1336


目录常用场景流行技术:ApachePOI和EasyExcelApachePOI简介EasyExcel简介JAVA解析Excel工具EasyExcel64M内存1分钟内读取75M(46W行25列)的ExcelExcel读写时候内存溢出其他开源框架使用复杂其他开源框架存在一些BUG修复不及时Excel格式分析格式分析核心原理解压文件读取通过文件形式避免将全部数据一次加载到内存抛弃不重要的数据POI-E
Milk Stork:https://www.ikjzd.com/w/2496
Parenthoods:https://www.ikjzd.com/w/2497
Filemail:https://www.ikjzd.com/w/2498
丈夫出轨妻子冷战好吗 老公出轨了妻子的聪明做法:http://www.30bags.com/a/250114.html
翁熄粗大第二篇十四章 握住她的腰猛烈撞击哼闷:http://www.30bags.com/m/a/249815.html
吧深一点老师今晚随你怎么弄 老师今天晚上让你桶个够:http://www.30bags.com/m/a/249772.html
深圳西涌沙滩可以烧烤吗:http://www.30bags.com/a/447903.html
365篇让他女朋友睡着的短篇小说:http://www.30bags.com/a/447904.html
40岁的王太后爱上了14岁的大叔:但小情人逼她自杀:http://www.30bags.com/a/447905.html
边陲之乡的董官村 一个西董花园就够你逛吃一天了:http://www.30bags.com/a/224141.html
口述:老公总怪我床上太急躁 怎么办老公床上急躁:http://lady.shaoqun.com/m/a/25783.html
男朋友在车里㖭下面 随着车的晃动一进一出:http://www.30bags.com/m/a/250124.html

No comments:

Post a Comment