读取Excel

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

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

  1. /**
  2. * Constructs a XSSFWorkbook object, by buffering the whole stream into memory
  3. * and then opening an {@link OPCPackage} object for it.
  4. *
  5. * <p>Using an {@link InputStream} requires more memory than using a File, so
  6. * if a {@link File} is available then you should instead do something like
  7. * <pre><code>
  8. * OPCPackage pkg = OPCPackage.open(path);
  9. * XSSFWorkbook wb = new XSSFWorkbook(pkg);
  10. * // work with the wb object
  11. * ......
  12. * pkg.close(); // gracefully closes the underlying zip file
  13. * </code></pre>
  14. */
  15. public XSSFWorkbook(InputStream is) throws IOException {
  16. super(PackageHelper.open(is));
  17.  
  18. beforeDocumentRead();
  19.  
  20. // Build a tree of POIXMLDocumentParts, this workbook being the root
  21. load(XSSFFactory.getInstance());
  22.  
  23. // some broken Workbooks miss this...
  24. if(!workbook.isSetBookViews()) {
  25. CTBookViews bvs = workbook.addNewBookViews();
  26. CTBookView bv = bvs.addNewWorkbookView();
  27. bv.setActiveTab(0);
  28. }
  29. }

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

  1. InputStream is = new FileInputStream(filePath);
  2. XSSFWorkbook workbook = new XSSFWorkbook(is);

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

  1. int countSheet = workbook.getNumberOfSheets();

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

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

工作表名称:String;

  1. /**
  2. * Excel解析后相关的Excel
  3. * <一句话功能简述>
  4. * <功能详细描述>
  5. *
  6. * @author
  7. * @version [版本号, 2019年6月26日]
  8. * @see [相关类/方法]
  9. * @since [产品/模块版本]
  10. */
  11. public class ExcelSheetStruct {
  12.  
  13. /**
  14. * sheet页名称
  15. */
  16. private String sheetName;
  17.  
  18. /**
  19. * 列表表头
  20. */
  21. private Map<String,String> headerMap;
  22.  
  23. /**
  24. * 列表数据
  25. */
  26. private List<Map<String,Object>> data;
  27. // 省略get和set
  28. }

三、工作表的数据读取

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

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

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

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

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

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

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

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

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

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

  1. /**
  2. * 读取Excel生成相应的数据集
  3. * <一句话功能简述>
  4. * <功能详细描述>
  5. * @param filePath
  6. * @return
  7. * @throws IOException
  8. * @see [类、类#方法、类#成员]
  9. * @author
  10. */
  11. public static List<ExcelSheetStruct> readXlsx(String filePath)
  12. throws IOException {
  13.  
  14. List<ExcelSheetStruct> allDataList = new ArrayList<>();
  15. XSSFWorkbook workbook = null;
  16. InputStream is = new FileInputStream(filePath);
  17. workbook = new XSSFWorkbook(is);
  18. int countSheet = workbook.getNumberOfSheets();
  19.  
  20. for (int numSheet = 0; numSheet < countSheet; numSheet++) {
  21. ExcelSheetStruct excelSheetStruct = new ExcelSheetStruct();
  22. List<Map<String, Object>> dataList = new ArrayList<>();
  23. excelSheetStruct.setData(dataList);
  24.  
  25. XSSFSheet xssfSheet = workbook.getSheetAt(numSheet);
  26. excelSheetStruct.setSheetName(xssfSheet.getSheetName());
  27.  
  28. //处理有数据区域的表格
  29. int firstRowNum = xssfSheet.getFirstRowNum();
  30. int lastRowNum = xssfSheet.getLastRowNum();
  31.  
  32. if (lastRowNum == 0) {
  33. continue;
  34. }
  35.  
  36. //循环处理该sheet页中的单行数据
  37. for (int row = firstRowNum; row <= lastRowNum; row++) {
  38. XSSFRow xssfRow = xssfSheet.getRow(row);
  39. if (row == firstRowNum) {
  40. excelSheetStruct.setHeaderMap(generateHeadLine(xssfRow));
  41. continue;
  42. }
  43. Map<String, Object> dateLine = generateDataLine(xssfRow, excelSheetStruct.getHeaderMap());
  44. dataList.add(dateLine);
  45. }
  46. allDataList.add(excelSheetStruct);
  47. }
  48. workbook.close();
  49. is.close();
  50. return allDataList;
  51.  
  52. }

导入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. mapreduce 变量共享

    mapreduce 全局变量共享 在编写MapReduce程序时,经常会遇到这样的问题,全局变量如何保存?如何让每个处理都能获取保存的这些全局变量?使用全局变量是不可避免的,但是 在MapRdeuce ...

  2. 使用Prometheus监控snmp

    获取snmp信息 首先获取需要监控的snmp的基本信息,假设基本信息如下: snmp服务IP: 1.1.1.1 snmp community: public snmp exportor部署地址: 2. ...

  3. Feign实现自定义错误处理

    关键操作 实现ErrorDecoder接口 问题和背景 最近项目中在大量使用Feign和OkHttp作为http客户端使用,开发效率得到显著的提升.但也面临一些问题,比如每个下游系统的异常返回方式不同 ...

  4. 《C++ 习题与解析》笔记

    目录 ####Chapter-1 C++语言概述(错题) ####Chapter-2 类和对象 ####Chapter-3 引用 ####Chapter-4 友元函数 #### Chapter-5 运 ...

  5. python基础知识的学习和理解

    参考链接:https://github.com/yanhualei/about_python/tree/master/python_learning/python_base   python基础知识笔 ...

  6. vue mint-ui 框架下拉刷新上拉加载组件的使用

    安装 npm i mint-ui -S 然后在main.js中引入 import MintUI from 'mint-ui' import 'mint-ui/lib/style.css' Vue.us ...

  7. java中各种常见的异常

    一.各种常见的异常 在上一节中程序如果你注意留意,程序抛出的异常是:java.lang.ArithmeticException.这个异常是在lang包中已经定义的.在lang包中还定义了一些我们非常常 ...

  8. C# 网络连接中异常断线的处理:ReceiveTimeout, SendTimeout 及 KeepAliveValues(设置心跳)

    C# 网络连接中异常断线的处理:ReceiveTimeout, SendTimeout 及 KeepAliveValues(设置心跳) 在使用 TcpClient 网络连接中常常会发生客户端连接异常断 ...

  9. Eclipse中js文件修改后浏览器不能及时更新的解决办法

    项目中js文件修改后浏览器不能及时更新的解决办法 转载:http://www.codeweblog.com/%E9%A1%B9%E7%9B%AE%E4%B8%ADjs%E6%96%87%E4%BB%B ...

  10. Visual Studio的语法着色终于调得赏心悦目

    代码可读性瞬间大大提升.Reshaper真的强大.