package com.haiyisoft.iecp.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DateUtil;
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.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

/**
* excel读取数据
*
* @author 白亚龙
*
* <p>
* 2018-04-19 白亚龙 新建
* </p>
*/

public class ReadExceTool {

/**
* 导出Excel文件的信息 形式为:List<List<Object>> 支持格式为 : xlsx,xls
* 第一层list为文件sheet信息 第二层list为一个sheet页面的信息 第三层为sheet内容某一行的信息
* 文件信息由上自下由左自右查找
* 分数数据暂时只能读取成小数保存
* @param File 输入文件
* @param String 文件后缀
* @return List<List<Object>> (最内层object为一个List<Object>数组)
*/
public List<List<Object>> readExcel(File file, String extension) {
List<List<Object>> fileObject = new java.util.ArrayList<List<Object>>();
Workbook wb = null;
// 读取文件格式判断,如果是excel文件则返回Workbook实例
wb = readFile(file, extension);
if(wb != null){
// 循环sheet页面,添加第一层list
for(int numSheet = 0; numSheet < wb.getNumberOfSheets(); numSheet++){
Sheet sheet = wb.getSheetAt(numSheet);
if(sheet == null){
continue;
}
/**
* column: sheet页面最大列数;
* 根据 sheet页最大行,最大列对页面进行循环处理
*/
List<Object> sheetObjects = new ArrayList<Object>();
// 获取数据最小列数
int startColumn = getFirstColNum(sheet, sheet.getLastRowNum());
// 获取数据最大列数
int endColumn = getLastColNum(sheet, sheet.getLastRowNum());
// 根据最大行数进行循环,将行数据数据放入第二层list
for(int i =0; i <= sheet.getLastRowNum(); i++){
Row row = sheet.getRow(i);
List<Object> rowValues = new ArrayList<Object>();
// 空行忽略
if(row == null){
continue;
}else {
// 每行内根据最大列数循环,将单元数据数据放入第三层list
for(int j = startColumn; j < endColumn; j++){
Cell cell = row.getCell(j);
// 空单元忽略
String cellValue = null;
if(cell == null) continue;
// 判断是否为合并单元格
if(isMergedRegion(sheet, i, j)){
// 合并单元格取值(所有单元格取第一个单元格的值,跨列合并单元格 只取第一个数据)
cellValue = getMergedValue(sheet, i, j);
}else{
// 单元格取值
cellValue = getValue(cell);
}
// 如果是跨列合并单元格 只取第一个数据
if(cellValue != null && cellValue.equals("ignoredData"))continue;
else rowValues.add(cellValue);
}
if (rowValues.size()>0) {
sheetObjects.add(rowValues);
}
}
}
if (sheetObjects.size()>0) {
fileObject.add(sheetObjects);
}
}
/*//遍历解析出来的list (数据验证)
for (List<Object> sheetObjects : fileObject) {
for (Object rowObjects : sheetObjects) {
List<Object> cellValues = (List<Object>) rowObjects;
for (int i = 0; i < cellValues.size(); i++) {
System.out.print(cellValues.get(i) + ",");
}
System.out.println();
}
System.out.println();
}*/
}
return fileObject;
}

/**
* 求Excel某一工作簿0~某行内的最小列数
* @param sheet 工作簿
* @param rowNum 行数
* @return
*/
private static int getFirstColNum(Sheet sheet, int lastRowNum) {
if(sheet == null){
return 0;
}
// 初始值设置为一个较大的值
int firstCol = 1000;
Row row = null;
// 根据行循环,取第一个非空值的最小下标
for(int i = 0; i <= lastRowNum; i++){
row = sheet.getRow(i);
if(row != null){
for(int j = 0; j < row.getLastCellNum(); j++){
if(row.getCell(j) != null){
if(firstCol > j){
firstCol = j;
break;
}
}
}
}
}
return firstCol;
}

/**
* 求Excel某一工作簿0~某行内的最大列数
* @param sheet 工作簿
* @param rowNum 行数
* @return
*/
private static int getLastColNum(Sheet sheet, int rowNum) {
if(sheet == null ){
return 0;
}
int lastCol = 0;
Row row = null;
for(int i = 0; i <= rowNum; i++){
row = sheet.getRow(i);
if(row != null){
int temp = row.getLastCellNum();
if(temp > lastCol){
lastCol = temp;
}
}
}
return lastCol;
}

/**
* 获取合并单元格的值
* @param sheet 工作簿
* @param rowNum 单元行
* @param columnIndex 单元列
* @return Object 单元值
*/
private static String getMergedValue(Sheet sheet, int rowNum,
int columnIndex) {
// 获取合并单元格个数
int mergeNum = sheet.getNumMergedRegions();
String value = null;
// 循环判断单元格所在合并单元格,合并单元格内所有单元格赋相同的值
for(int i = 0; i < mergeNum; i++){
CellRangeAddress range = sheet.getMergedRegion(i);
// 数据依次为合并单元格的第一列、最后一列、第一行、最后一行
int firstColumn = range.getFirstColumn();
int lastColumn = range.getLastColumn();
int firstRow = range.getFirstRow();
int lastRow = range.getLastRow();
// 判断是否在次单元格区间内
if(rowNum >= firstRow && rowNum <= lastRow){
// 所有单元格取第一个单元格的值,跨列合并单元格 只取第一个数据
if(columnIndex == firstColumn){
value = getValue(sheet.getRow(firstRow).getCell(firstColumn));
}else if(columnIndex > firstColumn && columnIndex <= lastColumn){
value = "ignoredData";
}
}
}
return value;
}

/**
* 判断是不是合并单元格
* @param sheet Excel工作簿
* @param rowNum 单元格行下标
* @param columnIndex 单元格列下标
* @return
*/
private static boolean isMergedRegion(Sheet sheet, int rowNum,
int columnIndex) {
// 获取合并单元格个数
int sheetMergedNum = sheet.getNumMergedRegions();
for(int i = 0; i < sheetMergedNum; i++){
CellRangeAddress range = sheet.getMergedRegion(i);
// 数据依次为合并单元格的第一列、最后一列、第一行、最后一行
int firstColumn = range.getFirstColumn();
int lastColumn = range.getLastColumn();
int firstRow = range.getFirstRow();
int lastRow = range.getLastRow();
// 判断是否在次单元格区间内,如果是则返回true
if(rowNum >= firstRow && rowNum <= lastRow){
if(columnIndex >= firstColumn && columnIndex <= lastColumn){
return true;
}
}
}
// 如果不在所有的合并单元格内则返回false
return false;
}

/**
* 读取文件类型,如果是excel则返回对象实例, 如果不是则返回null
* @param filePath 文件路径
* @return Workbook实例
*/
private static Workbook readFile(File file, String extension) {
Workbook wb = null;
if(file != null && extension != null && !extension.equals("")){
try {
InputStream inputStream = null;
inputStream = new FileInputStream(file);
if(extension.equals("xls")){
wb = new HSSFWorkbook(inputStream);
}else if(extension.equals("xlsx")){
wb = new XSSFWorkbook(inputStream);
}else{
wb = null;
}
} catch (FileNotFoundException e) {
System.out.println("未找到文件位置!");
e.printStackTrace();
} catch (IOException e) {
System.out.println("文件类型不正确,请重新选择!");
e.printStackTrace();
}
}
return wb;
}

/**
* 获取单元格的值,并格式化 日期格式不变 其他格式转换为字符串类型
* @param cell 单元格
* @return
*/
private static String getValue(Cell cell){
String cellValue = null;
// 格式化数据对象
DecimalFormat df = new DecimalFormat("0.######");
if(cell != null){
// 获取单元格数据类型
switch (cell.getCellType()) {
case Cell.CELL_TYPE_NUMERIC:
DateFormat formater = null;
Date d = cell.getDateCellValue();
if(cell.getCellStyle().getDataFormat() == 31){
formater = new SimpleDateFormat("yyyy年MM月dd日");
cellValue = formater.format(d);
}else if(cell.getCellStyle().getDataFormat() == 58){
formater = new SimpleDateFormat("MM月dd日");
cellValue = formater.format(d);
}else if(cell.getCellStyle().getDataFormat() == 14){
formater = new SimpleDateFormat("yyyy-MM-dd");
cellValue = formater.format(d);
}else if(cell.getCellStyle().getDataFormat() == 57){
formater = new SimpleDateFormat("yyyy年MM月");
cellValue = formater.format(d);
}else if(cell.getCellStyle().getDataFormat() == 20){
formater = new SimpleDateFormat("HH:mm");
cellValue = formater.format(d);
}else if(cell.getCellStyle().getDataFormat() == 32){
formater = new SimpleDateFormat("HH时mm分");
cellValue = formater.format(d);
}else if(cell.getCellStyle().getDataFormat() == 9){
cellValue = df.format(cell.getNumericCellValue()*100) + "%";
}else if(DateUtil.isCellDateFormatted(cell)){
formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
cellValue = formater.format(d);
}else{
cellValue = df.format(cell.getNumericCellValue());
}
break;
case Cell.CELL_TYPE_FORMULA:
try {
cellValue = df.format(cell.getNumericCellValue());
} catch (Exception e) {
cellValue = cell.getCellFormula();
}
break;
case Cell.CELL_TYPE_STRING:
cellValue = cell.getRichStringCellValue().getString();
break;
case Cell.CELL_TYPE_BLANK:
break;
case Cell.CELL_TYPE_ERROR:
break;
default:
cellValue = "";
break;
}
}
return cellValue;
}
}

使用poi读取Excel文件数据的更多相关文章

  1. 项目一:第四天 1、快递员的条件分页查询-noSession,条件查询 2、快递员删除(逻辑删除) 3、基于Apache POI实现批量导入区域数据 a)Jquery OCUpload上传文件插件使用 b)Apache POI读取excel文件数据

    1. 快递员的条件分页查询-noSession,条件查询 2. 快递员删除(逻辑删除) 3. 基于Apache POI实现批量导入区域数据 a) Jquery OCUpload上传文件插件使用 b) ...

  2. JAVA使用POI读取EXCEL文件的简单model

    一.JAVA使用POI读取EXCEL文件的简单model 1.所需要的jar commons-codec-1.10.jarcommons-logging-1.2.jarjunit-4.12.jarlo ...

  3. 上传读取Excel文件数据

    /// <summary> /// 上传读取Excel文件数据 /// 来自http://www.cnblogs.com/cielwater /// </summary> // ...

  4. 使用POI 读取 Excel 文件,读取手机号码 变成 1.3471022771E10

    使用POI 读取 Excel 文件,读取手机号码 变成 1.3471022771E10 [问题点数:40分,结帖人xieyongqiu]             不显示删除回复             ...

  5. 使用POI读取excel文件内容

    1.前言 项目中要求读取excel文件内容,并将其转化为xml格式.常见读取excel文档一般使用POI和JExcelAPI这两个工具.这里我们介绍使用POI实现读取excel文档. 2.代码实例: ...

  6. Java实现POI读取Excel文件,兼容后缀名xls和xlsx

    1.引入所需的jar包: maven管理项目的话直接添加以下坐标即可: <!-- https://mvnrepository.com/artifact/org.apache.poi/poi -- ...

  7. spring boot 使用 POI 读取Excel文件

    内容简介 本文主要介绍使用POI进行Excel文件的相关操作,涉及读取文件,获取sheet表格,对单元格内容进行读写操作,以及合并单元格的操作. Excel文件目录 Excel模板文件存了resour ...

  8. 使用jxl,poi读取excel文件

    作用:在java后台添加一个方法,读取导入的excel内容,根据需要返回相应的sql语句,以完成对临时表的插入操作. 使用jxl读取excel文件 package com.sixthf.bi.sapp ...

  9. VC6.0读取Excel文件数据

    啰嗦一下:本人所在公司从事碟式斯特林太阳能发电设备的研发与销售.单台设备图如下: 工作原理如下:整个设备大致可分为五个部分, 1.服务器,负责气象.发电等数据存取,电.网连接等处理: 2.气象站,通过 ...

随机推荐

  1. 一场由like引发的事故

    故事背景: 有一张用户级表,数据量在千万级别,而运营人员要查看这张表,其中有一项查询条件为根据“错误类型”(单值)查出所有包含这个类型的数据,而这个数据类型在数据库存放的方式类似于 “1,2,3,4, ...

  2. 主席树——求区间[l,r]不同数字个数的模板(向左密集 D-query)

    主席树的另一种用途,,(还有一种是求区间第k大,区间<=k的个数) 事实上:每个版本的主席树维护了每个值最后出现的位置 这种主席树不是以权值线段树为基础,而是以普通的线段树为下标的 /* 无修改 ...

  3. elemet-ui图标—特殊字符的unicode编码表

    https://blog.csdn.net/lurr88/article/details/79754811

  4. sqlserver2008 批量插入数据

    private DataTable GetTableSchema() { DataTable dt = new DataTable(); dt.Columns.AddRange(new DataCol ...

  5. kubernets HA集群手动部署

    来源:  https://www.cnblogs.com/yangxiaoyi/p/7606121.html  http://blog.51cto.com/newfly/2288088?source= ...

  6. this指向及改变this指向的方法

    一.函数的调用方式决定了 this 的指向不同,但总的原则,this指的是调用函数的那个对象: 1.普通函数调用,此时 this 指向 全局对象window function fn() { conso ...

  7. 在无向图中找最短桥(tarjan)

    题目:hdu 4738 题目意思:  曹操有N个岛,这些岛用M座桥连接起来 每座桥有士兵把守(也可能没有) 周瑜想让这N个岛不连通,但只能炸掉一座桥 并且炸掉一座桥需要派出不小于守桥士兵数的人去 解题 ...

  8. Docker入门到实践

    1.什么是Docke 1.网上有很多 2.为什么要使用Docker? 优点 更高效的利用系统资源 更快速的启动时间 一致的运行环境 持续交付和部署 更轻松的迁移 更轻松的维护和扩展 3.Docker的 ...

  9. Linux环境下vi/vim编辑器常用命令

    使用vi文本编辑器 配置文件是Linux系统中的显著特征之一,其作用有点类似于Windows系统中的注册表,只不过注册表是集中管理,而配置文件采用了分散的自由管理方式.那么如何使用Linux字符操作界 ...

  10. Alpha冲刺——代码规范、冲刺任务与计划

    代码规范 作业描述 课程 软件工程1916|W(福州大学) 团队名称 修!咻咻! 作业要求 项目Alpha冲刺(团队) 团队目标 切实可行的计算机协会维修预约平台 开发工具 Eclipse 团队信息 ...