以下内容均来自实际项目需求,记录下,网上找的读取Excel会出现不少问题,下面代码是经过好多次测试改进的符合现在项目的代码,如有不同要求,请自行修改,代码均只去掉了包名。
注:我们的Excel 第一行是表头,其他行是数据
1、第一行遇到空列,后面的内容自动忽略掉,
2、如果数据中间有一行空白行,继续读,只有连续两行活着以上是空白行,下面的就忽略掉不读取了。

完整代码如下

WDWUtil.java

/*** 判断Excel 文件的版本* Created by Administrator on 2018/7/4.*/
public class WDWUtil {// @描述:是否是2003的excel,返回true是2003public static boolean isExcel2003(String filePath) {return filePath.matches("^.+\\.(?i)(xls)$");}//@描述:是否是2007的excel,返回true是2007public static boolean isExcel2007(String filePath) {return filePath.matches("^.+\\.(?i)(xlsx)$");}
}
ExcelUtils

此类适用于预览数据和真正上传数据(预览数据时读取前一百条数据,正常上传读取全部数据)

其中包含空行空列的处理逻辑,代码中均加了注释

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 java.io.*;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** Excel 文件的处理* Created by Administrator on 2018/7/4.*/
public class ExcelUtils {//总行数private int totalRows = 0;//总条数private int totalCells = 0;//错误信息接收器private String errorMsg;// 是否是预览private boolean isPriview = true;//构造方法public ExcelUtils() {}//构造方法public ExcelUtils(boolean isPriview) {this.isPriview=isPriview;}//获取总行数public int getTotalRows() {return totalRows;}//获取总列数public int getTotalCells() {return totalCells;}//获取错误信息public String getErrorInfo() {return errorMsg;}/*** 验证EXCEL文件** @param filePath* @return*/public boolean validateExcel(String filePath) {if (filePath == null || !(WDWUtil.isExcel2003(filePath) || WDWUtil.isExcel2007(filePath))) {errorMsg = "文件名不是excel格式";return false;}return true;}/*** 读EXCEL文件** @param* @return*/public Map<String, Object> getExcelInfo(String fileName, String tmpFilePath) {Map<String, Object> result = new HashMap<String, Object>();File fa = new File(tmpFilePath);InputStream is = null;try {is= new FileInputStream(fa);} catch (FileNotFoundException e) {e.printStackTrace();}try {//验证文件名是否合格if (!validateExcel(fileName)) {errorMsg = "文件不是excel格式";return null;}//根据文件名判断文件是2003版本还是2007版本boolean isExcel2003 = true;if (WDWUtil.isExcel2007(fileName)) {isExcel2003 = false;}// 获取excel内容Workbook wb = getExcelInfo(is, isExcel2003);List customerList = null;List titleList = null;Map columnstypes = null;// 读取标题信息 其中也设置了有效列数量titleList = readExcelTitle(wb);//读取Excel信息customerList = readExcelValue(wb);if(isPriview){columnstypes = getColumnType(wb);customerList.add(0, columnstypes);}result.put("error", errorMsg);result.put("tablename", fileName.substring(0, fileName.lastIndexOf('.')));result.put("schema", titleList);result.put("data", customerList);result.put("columnstypes", columnstypes);is.close();} catch (Exception e) {e.printStackTrace();} finally {if (is != null) {try {is.close();} catch (IOException e) {is = null;e.printStackTrace();}}}return result;}/*** 根据excel里面的内容** @param is          输入流* @param isExcel2003 excel是2003还是2007版本* @return*/public Workbook getExcelInfo(InputStream is, boolean isExcel2003) {/** 根据版本选择创建Workbook的方式 */Workbook wb = null;try {//当excel是2003时if (isExcel2003) {wb = new HSSFWorkbook(is);} else {  //当excel是2007时wb = new XSSFWorkbook(is);}return wb;} catch (IOException e) {e.printStackTrace();}return wb;}/*** 读取Excel内容** @param wb* @return*/private List readExcelValue(Workbook wb) {//得到第一个shellSheet sheet = wb.getSheetAt(0);//得到Excel的行数this.totalRows = sheet.getPhysicalNumberOfRows();//得到Excel的列数(前提是有行数)// 0816 已经在获取标题的时候设置了有效列  totalCellsif (isPriview && totalRows > 100) {totalRows = 101;}// 记录空行 规则 如果空行大于1行 下面的视为垃圾数据 忽略 20180820  yunguang modifiedint blankLine=0;List valueList = new ArrayList();//循环Excel行数,从第二行开始。标题不入库for (int r = 1; r < totalRows; r++) {Row row = sheet.getRow(r);if (row == null) {// 遇到空白行 获取的行数加1this.totalRows++;blankLine++;if (blankLine > 1) {// totalrows 重新定义总行数  20180820  yunguang modifiedthis.totalRows = r;break;}continue;} else {  // 无空白行 重置计数器blankLine = 0;}List temp = new ArrayList();// 标记是否为插入的空白行 识别规则 插入的数据后第一个单元格为空boolean addFlag = false;//循环Excel的列for (int c = 0; c < this.totalCells; c++) {Cell cell = row.getCell(c);if (null != cell) {String cellValue = getCellValue(cell);// 针对又见插入的行 poi默认它不算空行 判断该行如果有一个 不为空 该条记录视为有效 20180820  yunguang modifiedif ("".equals(cellValue) && (!addFlag)) {addFlag = false;} else {addFlag = true;}if("".equals(cellValue)){temp.add("\\N");}else {temp.add(cellValue);}} else {temp.add("\\N");}}if (addFlag) { // 判断是否为有效数据valueList.add(temp);}}return valueList;}/*** 读取Excel表头** @param wb* @return*/private List readExcelTitle(Workbook wb) {//得到第一个shellSheet sheet = wb.getSheetAt(0);//得到Excel的行数this.totalRows = sheet.getPhysicalNumberOfRows();//得到Excel的列数(前提是有行数)if (totalRows >= 1 && sheet.getRow(0) != null) {this.totalCells = sheet.getRow(0).getPhysicalNumberOfCells();}List titleList = new ArrayList();// 读取标题Row row = sheet.getRow(0);if (row == null) return null;//循环Excel的列for (int c = 0; c < this.totalCells; c++) {Map temp = new HashMap();Cell cell = row.getCell(c);if (null != cell) {temp.put("name", getCellValue(cell));titleList.add(temp);}else {// 0816  遇到一个空白标题 结束this.totalCells=c;break;}}return titleList;}/*** 读取Excel表头** @param wb* @return*/private Map getColumnType(Workbook wb) {//得到第一个shellSheet sheet = wb.getSheetAt(0);//得到Excel的行数this.totalRows = sheet.getPhysicalNumberOfRows();//得到Excel的列数(前提是有行数)if (totalRows >= 1 && sheet.getRow(0) != null) {this.totalCells = sheet.getRow(0).getPhysicalNumberOfCells();}if (this.totalRows > 101) {totalRows = 101;}// 0,stringMap rowColumns = new HashMap();// 记录空行 规则 如果空行大于1行 下面的视为垃圾数据 忽略 20180820  yunguang modifiedint blankLine=0;//循环Excel行数,从第二行开始。标题不入库for (int r = 1; r < totalRows; r++) {Row row = sheet.getRow(r);if (row == null) {this.totalRows++;blankLine ++;if (blankLine > 1) {// totalrows 重新定义总行数  20180820  yunguang modifiedthis.totalRows = r;break;}continue;}else {  // 无空白行 重置计数器blankLine = 0;}//循环Excel的列for (int c = 0; c < this.totalCells; c++) {Cell cell = row.getCell(c);if (null != cell) {String cellValue = getCellValue(cell);Object value = rowColumns.get(c);String val = (String) value;String valType =FileOperateUtil.getType(cellValue);if (!"string".equals(val)) {if("string".equals(valType)){rowColumns.put(c,valType);}else if(!"double".equals(val)){rowColumns.put(c,valType);}}}else {rowColumns.put(c,"string");}}}return rowColumns;}private String getCellValue(Cell cell) {String value = "";SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");switch (cell.getCellTypeEnum()) {case STRING:value = cell.getRichStringCellValue().getString();break;case NUMERIC:if ("General".equals(cell.getCellStyle().getDataFormatString())) {// 数据格式 DecimalFormat df = new DecimalFormat("#.########");value = df.format(cell.getNumericCellValue())+"";} else if ("m/d/yy".equals(cell.getCellStyle().getDataFormatString())) {value = sdf.format(cell.getDateCellValue())+"";} else {// 针对十位数以上的数字出现科学记数法的处理 20180820  yunguang modifiedvalue =   new DecimalFormat("#").format(cell.getNumericCellValue());}break;case BOOLEAN:value = cell.getBooleanCellValue() + "";break;case BLANK:value = "";break;default:value = cell.toString();break;}return value;}
}
CSVUtils
import com.csvreader.CsvReader;
import info.monitorenter.cpdetector.io.*;
import lombok.extern.slf4j.Slf4j;import java.io.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** CSV 文件的操作类* Created by Administrator on 2018/7/10.*/
@Slf4j
public class CSVUtils {// 预览或者正式上传(true 为预览)private boolean isPriview = true;public CSVUtils() {}public CSVUtils(boolean isPriview) {this.isPriview = isPriview;}/*** 导出**** @param file     @param file csv文件(路径+文件名),csv文件不存在会自动创建* @param dataList 数据* @return*/public static boolean exportCsv(File file, List<String> dataList) {boolean isSucess = false;FileOutputStream out = null;OutputStreamWriter osw = null;BufferedWriter bw = null;try {out = new FileOutputStream(file);osw = new OutputStreamWriter(out, "UTF-8");bw = new BufferedWriter(osw);if (dataList != null && !dataList.isEmpty()) {for (String data : dataList) {bw.append(data).append("\r");}}isSucess = true;} catch (Exception e) {isSucess = false;} finally {if (bw != null) {try {bw.close();bw = null;} catch (IOException e) {e.printStackTrace();}}if (osw != null) {try {osw.close();osw = null;} catch (IOException e) {e.printStackTrace();}}if (out != null) {try {out.close();out = null;} catch (IOException e) {e.printStackTrace();}}}return isSucess;}/*** 导入** @param file csv文件(路径+文件)* @return*/public static List<String> importCsv(File file) {List<String> dataList = new ArrayList<String>();BufferedReader br = null;try {InputStreamReader reader = new InputStreamReader(new FileInputStream(file), "UTF-8");br = new BufferedReader(reader);String line = "";while ((line = br.readLine()) != null) {dataList.add(line);}} catch (Exception e) {e.printStackTrace();} finally {if (br != null) {try {br.close();br = null;} catch (IOException e) {e.printStackTrace();}}}return dataList;}/*** 调用该方法的模块:*  本地调用* 功能描述: *  获取该文件内容的编码格式* @param:* @return: * @auther: solmyr* @date: 2018/8/16 下午3:29*/private Charset getFileEncode(String filePath) {try {File file = new File(filePath);CodepageDetectorProxy detector = CodepageDetectorProxy.getInstance();detector.add(new ParsingDetector(false));detector.add(JChardetFacade.getInstance());detector.add(ASCIIDetector.getInstance());detector.add(UnicodeDetector.getInstance());Charset charset = null;charset = detector.detectCodepage(file.toURI().toURL());if (charset != null) {return charset;}} catch (Exception e) {log.error("get file encode error, filePath: " + filePath, e);}return Charset.forName("UTF-8");}/*** 获取 csv 文件信息** @param fileName 文件名* @param tmpFilePath    接收到的文件对象* @return*/public Map<String, Object> getCSVInfo(String fileName, String tmpFilePath) {Map<String, Object> result = new HashMap<String, Object>();String filePath = tmpFilePath;List titleList = new ArrayList();List valueList = new ArrayList();Map rowColumns = new HashMap();try {Charset fileEncode = getFileEncode(filePath);File fa = new File(filePath);FileInputStream fi = new FileInputStream(fa);CsvReader cr = new CsvReader(fi, fileEncode);int i = 0;while (cr.readRecord()) {if (i == 0) {String[] rs = cr.getValues();for (String s : rs) {Map temp = new HashMap();temp.put("name", s);titleList.add(temp);}} else {if (isPriview && i > 100) break;List temp = new ArrayList();String[] rs = cr.getValues();int k = 0;for (String s : rs) {Object value = rowColumns.get(k);String val = (String) value;if (!"string".equals(val)) {if(!"double".equals(val)){rowColumns.put(k, FileOperateUtil.getType(s));}}temp.add(s);k++;}valueList.add(temp);}i++;}cr.close();fi.close();} catch (IOException e) {e.printStackTrace();}if (isPriview){valueList.add(0, rowColumns);}result.put("error", null);result.put("tablename", fileName.substring(0, fileName.lastIndexOf('.')));result.put("schema", titleList);result.put("data", valueList);result.put("columnstypes", rowColumns);return result;}
}

调用代码接口:

import org.springframework.web.multipart.MultipartFile;import java.util.Map;/*** 对上传的文件进行格式解析* Created by Administrator on 2018/7/4.*/
public interface ExcelCsvFileParserService {/*** 获取上传文件的目录* @param userId 用户ID* @param file 用户上传的文件* @return*/String getUploadPath(String userId,MultipartFile file);/*** 上传文件取消获取上传完成* 删除临时文件* @param userId 用户ID* @param fileName 用户上传的文件名* @return*/boolean handlePreviewCancel(String userId,String fileName);/*** 获取处理后的结果* @param isPreview* @param filename* @param fullPath* @return*/Map<String, Object> HandlerFile(boolean isPreview,String filename,String fullPath);
}

实现类如下:

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;import java.io.File;
import java.io.IOException;
import java.util.Map;/*** Created by Administrator on 2018/7/4.*/
@Service
@Slf4j
public class ExcelCsvFileParserServiceImpl implements ExcelCsvFileParserService {@Overridepublic Map<String, Object> HandlerFile(boolean isPreview,String filename,String fullPath) {//  判断文件类型 是excel 文件还是cscif (".csv".equals(filename.toLowerCase().substring(filename.toLowerCase().lastIndexOf('.')))) {return new CSVUtils(isPreview).getCSVInfo(filename, fullPath);} else {return new ExcelUtils(isPreview).getExcelInfo(filename, fullPath);}}@Overridepublic boolean handlePreviewCancel(String userId,String fileName){boolean isDelete  = false;// 获取上传目录File upload = FileOperateUtil.getAbsoluteUploadPath();// 临时存放文件目录String tmpPath= upload + File.separator +userId+File.separator;String fullPath = tmpPath + fileName;File tempFilePath = new File(fullPath);if (tempFilePath.exists()) {isDelete = tempFilePath.delete();}return isDelete;}@Overridepublic String getUploadPath(String userId, MultipartFile file) {String filename = file.getOriginalFilename();// 获取上传目录File upload = FileOperateUtil.getAbsoluteUploadPath();// 临时存放文件目录String tmpPath= upload + File.separator +userId+File.separator;File tempFilePath = new File(tmpPath);if (!tempFilePath.exists()) tempFilePath.mkdirs();String fullPath = tmpPath + filename;try {// 保存临时文件file.transferTo(new File(fullPath));} catch (IOException e) {e.printStackTrace();}return fullPath;}}

如有性能问题或者隐含bug,期待评论拍砖!!!

补充:

***********************************************************************************************************************************

poem文件增加如下(import com.csvreader.CsvReader的jar包

     <dependency><groupId>net.sourceforge.javacsv</groupId><artifactId>javacsv</artifactId><version>2.0</version></dependency>

补充 getType 方法

// FileOperateUtil
public static String getType(String str) {// 优先判断日期类型String patterndate1 = "\\d{4}(-)\\d{2}(-)\\d{2}\\s\\d{2}(:)\\d{2}(:)\\d{2}";String patterndate2 = "\\d{4}(-)\\d{2}(-)\\d{2}";if (str.matches(patterndate1) || str.matches(patterndate2)) {return FileType.DATE;} else {// 先判断double类型if (str.contains(".")) {try{Double.parseDouble(str);return FileType.DOUBLE;}catch (Exception exd){return FileType.STRING;}} else {try {Long.parseLong(str);return FileType.BIGINT;} catch (Exception e) {try {Double.parseDouble(str);return FileType.DOUBLE;} catch (Exception ex) {return FileType.STRING;}}}}}

Java 常用的工具类—判断Excel版本读取Excel/CSV文件相关推荐

  1. Java常用加密算法工具类

    import java.io.IOException; import java.math.BigInteger; import java.security.MessageDigest; import ...

  2. java常用时间工具类

    /*** LocalDateTime工具类** @author Code13* @date 2019-11-10 21:10*/ public final class LocalDateTimeUti ...

  3. 使用工具类按一定规则读取Excel文件

    工作中需要按照功能分类去批量新增数据,数据的载体为Excel文件.现编写一个工具类按照业务规则来读取并处理Excel文件数据. 目录 1.工具类 2.具体实现 总结 1.工具类 在读取文件这里,使用h ...

  4. 28个Java常用的工具类

    源码下载:http://pan.baidu.com/s/1pJLSczD Base64.java Base64DecodingException.java CConst.java CharTools. ...

  5. java tailer apache_工具类commons-io的Tailer用来监控文件

    一.前言: 使用Commons-io的monitor下的相关类可以处理对文件进行监控,它采用的是观察者模式来实现的 1.可以监控文件夹的创建.删除和修改 2.可以监控文件的创建.删除和修改 3.采用的 ...

  6. java项目常用的工具类

    前言 在开发过程中,我们会遇到很多繁琐或者棘手的问题,但是,这些问题往往会存在一些便捷的工具类,来简化我们的开发,下面是我工作中经常使用到的工具类 常用工具类 日期工具类 import java.te ...

  7. java常用工具类和Hutool常用的工具类整理

    java常用工具类和Hutool常用的工具类整理 1.java常用工具类 1.1 Scanner类 /*** Scanner 类*/@Testpublic void testScanner() {Sc ...

  8. java web 项目 常用 小工具类 ~~~~

    java web 项目 常用 小工具类 ~~~~ 一 .DateUtil  日期工具类 package com.devframe.common.util;import java.text.Simple ...

  9. java中常用的工具类

    1. 常用零散工具类 1.1[DateUtil.java]日期处理的工具类 /*** 时间日期处理工具* String -> Date* Date -> String* 以及生成含有日期的 ...

最新文章

  1. Cissp-【第6章 安全评估与测试】-2021-3-15(661页-706页)
  2. 简单使用Modelsim跑个仿真
  3. sql python 教程_Python SQLAlchemy ORM教程(3)
  4. linux amd64目录,解决ubuntu amd64 14.04 bash./ 没有那个文件或目录 的方法(含ia32-libs包的安装方法)...
  5. 原生js对数组操作(find,findIndex)
  6. 仿Hex-Editor,实现简单地二进制文件查看器JHexer
  7. model.most_similar
  8. 什么是IDU和ODU
  9. 【编程实践】一致性哈希(hash)算法实现
  10. RN 在Android Studio运行闪退后报错
  11. Android TextView重写onMeasure和onDraw显示无拉伸图片(含实现代码链接)
  12. EMV技术学习和研究(九)终端行为分析
  13. 转:传智播客—jbpm与OA项目(七)
  14. BZOJ 3698(XWW的难题-上下界网络流+经典建模)
  15. php 时间戳 星座,十二个星座的时间划分与性格总括
  16. SQL函数 LTRIM和RTRIM的用法
  17. 山西2019数据结构专升本_山西省2017年专升本数据结构真题
  18. Win7系统下使用猎豹浏览器兼容模式替代IE浏览器
  19. 半年收入超2亿RMB 独立游戏开发者的艰苦创业路
  20. 郭为出席数字金融创新应用与发展研讨会,谈数字技术助力普惠金融

热门文章

  1. 如何从区块链上数据识别出套利行为或者抢跑三明治交易
  2. mediaplayer参数设置说明
  3. 新装电脑系统,会自动安装乱七八糟的软件问题处理法
  4. Cocos2d-x学习笔记(三)浅析动作类CCAction(2)
  5. 聚亿美匠心时代,聚亿美用心打造未来
  6. 南方科技大学计算机系优秀毕业生,南科大2020届本科十佳毕业生评选结果揭晓...
  7. PatriotCTF
  8. Qt信号槽机制详解及案例
  9. 【2018慢性病与信息大会】中国通信标准化协会常务副秘书长兼副理事长 代晓慧致辞...
  10. Hive系列之HSQL转换成MapReduce过程