读取Excel

思路:先读取整个Excel,即工作簿,再依次读取其中的每个工作表Sheet,最后读取工作表内的表格。

一、读取工作簿
利用流读取指定目录中的工作簿,并写入内存。

   /**
* Constructs a XSSFWorkbook object, by buffering the whole stream into memory
* and then opening an {@link OPCPackage} object for it.
*
* <p>Using an {@link InputStream} requires more memory than using a File, so
* if a {@link File} is available then you should instead do something like
* <pre><code>
* OPCPackage pkg = OPCPackage.open(path);
* XSSFWorkbook wb = new XSSFWorkbook(pkg);
* // work with the wb object
* ......
* pkg.close(); // gracefully closes the underlying zip file
* </code></pre>
*/
public XSSFWorkbook(InputStream is) throws IOException {
super(PackageHelper.open(is)); beforeDocumentRead(); // Build a tree of POIXMLDocumentParts, this workbook being the root
load(XSSFFactory.getInstance()); // some broken Workbooks miss this...
if(!workbook.isSetBookViews()) {
CTBookViews bvs = workbook.addNewBookViews();
CTBookView bv = bvs.addNewWorkbookView();
bv.setActiveTab(0);
}
}

针对源码,先生产InputStream,再读取:

InputStream is = new FileInputStream(filePath);
XSSFWorkbook workbook = new XSSFWorkbook(is);

二、读取工作薄中工作表,依次读取,先要知道到底有几个? 此处,需要对XSSFWorkbook类有基本的了解。(建议看一下源码)

int countSheet = workbook.getNumberOfSheets();

for循环读取每个工作表。
思考:需要怎样的数据结构才能优雅的存放其中的数据?
思考一下工作表中存放的数据:主流的是表格和表格下的数据。
进一步思考这个表格的数据用什么样的数据结构?
表格进一步分析,表格有表头和非表头数据组成,由于表头需要对应实体映射,需要单独处理。
因此表头采用Map存储(此处下面需要继续分析),同样一行数据也用Map处理,多行数据放入List
至此:工作表的数据结构清晰了。

表头:Map<String,object>;
非数据多行:List<Map,Object>;

工作表名称:String;

/**
* Excel解析后相关的Excel
* <一句话功能简述>
* <功能详细描述>
*
* @author
* @version [版本号, 2019年6月26日]
* @see [相关类/方法]
* @since [产品/模块版本]
*/
public class ExcelSheetStruct { /**
* sheet页名称
*/
private String sheetName; /**
* 列表表头
*/
private Map<String,String> headerMap; /**
* 列表数据
*/
private List<Map<String,Object>> data;
// 省略get和set
}

三、工作表的数据读取

for (int numSheet = 0; numSheet < countSheet; numSheet++) {
// 获取Sheet,创建Sheet数据结构
XSSFSheet xssfSheet = workbook.getSheetAt(numSheet);
ExcelSheetStruct excelSheetStruct = new ExcelSheetStruct();
excelSheetStruct.setSheetName(xssfSheet.getSheetName());
}

再获取表格数据,先得获取有效区域。
思考:到底是先从行开始,还是先从列开始,即第一维度是行还是列?
此处先从行开始,因为行在Sheet中是数字。(注:有效行是当前行数字减1)

//处理有数据区域的表格
int firstRowNum = xssfSheet.getFirstRowNum();
int lastRowNum = xssfSheet.getLastRowNum();
// 处理表头和非表头,第一维度“行”
for (int row = firstRowNum; row <= lastRowNum; row++) {}

再for循环内,获取列号(第二维度),就能唯一定位到数据,进行获取。
这边先获取表头

    /**
* 根据所给的首行,生成具体的数据结构
* <一句话功能简述>
* <功能详细描述>
* @param xssfRow
* @return
* @see [类、类#方法、类#成员]
* @author
*/
public static Map<String, String> generateHeadLine(XSSFRow xssfRow) {
Map<String, String> headerMap = new HashMap<>();
// 获取开始列和结束列
int firstCellNum = xssfRow.getFirstCellNum();
int lastCellNum = xssfRow.getLastCellNum();
for (int cellNum = firstCellNum; cellNum < lastCellNum; cellNum++) {
Cell cell = xssfRow.getCell(cellNum, XSSFRow.CREATE_NULL_AS_BLANK);
// key——列号,value——数据
headerMap.put(String.valueOf(cellNum), cell.getStringCellValue());
}
return headerMap;
}

同理,获取非表头。此处把表头和下面列的数据进行关联。即Map<String,Object> = HashMap<"表头","表头当前列下面的一个数据(当前cell的值)">

    /**
* 对数据行的处理,根据头行数据,将数据与行列表结合起来
* <一句话功能简述>
* <功能详细描述>
* @param xssfRow
* @return
* @see [类、类#方法、类#成员]
* @author
*/
public static Map<String, Object> generateDataLine(XSSFRow xssfRow, Map<String, String> headerLine) {
Map<String, Object> mapDate = new HashMap<>();
// 此处也是读取列,用上面有不同之处,这边不是顺序读取,是按照表头存储的数据的key(列号)
for (String key : headerLine.keySet()) {
Cell cell = xssfRow.getCell(Integer.parseInt(key), XSSFRow.CREATE_NULL_AS_BLANK);
cell.setCellType(Cell.CELL_TYPE_STRING);
// HashMap<"表头的值","当前的值">
mapDate.put(headerLine.get(key), cell.getStringCellValue());
}
return mapDate;
}

读取完一行非表头数据需要继续读取,最后添加到非标头数据结构中List<Map>;

//循环处理该sheet页中的单行数据
for (int row = firstRowNum; row <= lastRowNum; row++) {
XSSFRow xssfRow = xssfSheet.getRow(row);
if (row == firstRowNum) {
// 处理完表头数据,把它添加到Sheet中
excelSheetStruct.setHeaderMap(generateHeadLine(xssfRow));
continue;
}
Map<String, Object> dateLine = generateDataLine(xssfRow, excelSheetStruct.getHeaderMap());
// 整合非表头数据
dataList.add(dateLine);
}
// 处理完非表头数据,把它添加到Sheet中
allDataList.add(excelSheetStruct);

至此数据单个Sheet处理完毕,回顾代码:

/**
* 读取Excel生成相应的数据集
* <一句话功能简述>
* <功能详细描述>
* @param filePath
* @return
* @throws IOException
* @see [类、类#方法、类#成员]
* @author
*/
public static List<ExcelSheetStruct> readXlsx(String filePath)
throws IOException { List<ExcelSheetStruct> allDataList = new ArrayList<>();
XSSFWorkbook workbook = null;
InputStream is = new FileInputStream(filePath);
workbook = new XSSFWorkbook(is);
int countSheet = workbook.getNumberOfSheets(); for (int numSheet = 0; numSheet < countSheet; numSheet++) {
ExcelSheetStruct excelSheetStruct = new ExcelSheetStruct();
List<Map<String, Object>> dataList = new ArrayList<>();
excelSheetStruct.setData(dataList); XSSFSheet xssfSheet = workbook.getSheetAt(numSheet);
excelSheetStruct.setSheetName(xssfSheet.getSheetName()); //处理有数据区域的表格
int firstRowNum = xssfSheet.getFirstRowNum();
int lastRowNum = xssfSheet.getLastRowNum(); if (lastRowNum == 0) {
continue;
} //循环处理该sheet页中的单行数据
for (int row = firstRowNum; row <= lastRowNum; row++) {
XSSFRow xssfRow = xssfSheet.getRow(row);
if (row == firstRowNum) {
excelSheetStruct.setHeaderMap(generateHeadLine(xssfRow));
continue;
}
Map<String, Object> dateLine = generateDataLine(xssfRow, excelSheetStruct.getHeaderMap());
dataList.add(dateLine);
}
allDataList.add(excelSheetStruct);
}
workbook.close();
is.close();
return allDataList; }

导入Excel——解析Excel的更多相关文章

  1. oracle xmltype导入并解析Excel数据--前言

    通常,很多的时候,我们需要导入Excel数据到系统中,但是Excel数据需要我们去各种校验,比如身份证校验,手机号码校验等等. 校验失败的数据,提供Excel导出错误原因,提示给用户. 如此,如果校验 ...

  2. oracle xmltype导入并解析Excel数据 (四)特别说明

    1.Excel导出,此处没有给出 2.错误原因在中间表,T_EXCEL_IMPORT_GENERATION,其中errormsg不为空的数据 3,中间表入库过程: 需要自己实现,为一个存储过程,存储过 ...

  3. oracle xmltype导入并解析Excel数据 (一)创建表与序

    表说明: T_EXCEL_IMPORT_DATASRC: Excel数据存储表,(使用了xmltype存储Excel数据) 部分字段说明: BUSINESSTYPE: Excel模板类型,一个Exce ...

  4. oracle xmltype导入并解析Excel数据 (三)解析Excel数据

    包声明 create or replace package PKG_EXCEL_UTILS is -- Author: zkongbai-- Create at: 2016-07-06-- Actio ...

  5. oracle xmltype导入并解析Excel数据 (二)规则说明

    规则表字段说明如下: 其中RULE_FUNC_CUSTOMIZE表示,用户自己写函数,去判断数据是否合法,存储的是函数的名字 此函数的参数只有一个,该列的值,字段类型是Varchar2, 校验失败的话 ...

  6. 利用 js-xlsx 实现 Excel 文件导入并解析Excel数据成json格式的数据并且获取其中某列数据

    演示效果参考如下:XML转JSON 另一个搭配SQL实现:http://sheetjs.com/sexql/index.html 详细介绍: 1.首先需要导入js <script src=&qu ...

  7. 导入Excel——解析Excel——优化

    package com.it.excel.excelLearn; import java.io.FileInputStream; import java.io.IOException; import ...

  8. oracle xmltype导入并解析Excel数据 (五)中间表数据入库

    此处给出例子,具体根据业务需求 create or replace procedure P_CART_Sheet1(p_id in NUMBER) is--车辆管理功能v_str varchar2(4 ...

  9. Excel解析与导入导出

    第三次结对编程作业 结对成员: 031302610黄志鹏 031302603 陈波 功能分析 1.将初始排课表excel导入系统数据库 2.将系统数据库的排课数据显示在web界面 实现思路 一.实现将 ...

随机推荐

  1. scrapy中间件中发送邮件

    背景介绍:之前写过通过通过scrapy的扩展发送邮件,在爬虫关闭的时候发送邮件.那个时候有个问题就是MailSender对象需要return出去.这次需要在中间件中发送邮件,但是中间件中不能随便使用r ...

  2. python 将列表里的字典元素合并为一个字典

    python 将列表里的字典元素合并为一个字典 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn. ...

  3. SpringBoot:4.SpringBoot整合Mybatis实现数据库访问

    在公司项目开发中,使用Mybatis居多.在 SpringBoot:3.SpringBoot使用Spring-data-jpa实现数据库访问 中,这种jpa风格的把sql语句和java代码放到一起,总 ...

  4. - XML 解析 总结 DOM SAX PULL MD

    目录 目录 XML 解析 总结 DOM SAX PULL MD 几种解析方式简介 要解析的内容 DOM 解析 代码 输出 SAX 解析 代码 输出 JDOM 解析 代码 输出 DOM4J 解析 代码 ...

  5. 命令创建.net core3.0 web应用详解(超详细教程)

    原文:命令创建.net core3.0 web应用详解(超详细教程) 你是不是曾经膜拜那些敲几行代码就可以创建项目的大神,学习了命令创建项目你也可以成为大神,其实命令创建项目很简单. 1.cmd命令行 ...

  6. Kafka Streams的Data Types and Serialization

    Avro <repositories> <repository> <id>confluent</id> <url>http://packag ...

  7. SQL语句--删除掉重复项只保留一条

    用SQL语句,删除掉重复项只保留一条 在几千条记录里,存在着些相同的记录,如何能用SQL语句,删除掉重复的呢1.查找表中多余的重复记录,重复记录是根据单个字段(peopleId)来判断 select ...

  8. (原创)MODBUS-TCP协议分析

  9. js原生Ajax(十四)

    一.XMLHttpRequest    [使用XMLHttpRequest时,必须将html部署到web服务器中]1) 指定请求1.实例化eg: var http = new XMLHttpReque ...

  10. js学习之存储

    一.Cookie和Session的区别 1.cookie数据存放在客户的浏览器上,session数据放在服务器上(一般以内存.数据库.文件形式). 2.session会在一定时间内保存在服务器上.当访 ...