POI 读取 Excel 文件(2003版本与2007版本的差异之处)

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

已整理成完整项目,并进行了优化。看参考地址:

https://gitee.com/andy_longjie/exceltools   或者 https://github.com/youmulongjie/exceltools

我们在做用POI读物 Excel文件时,往往会忽略了Excel的版本,到底是2003还是2007。于是在读取或写入Excel文件时,用2003版本的Excel和用2007版本的Excel文件,会出现不兼容情况。抛出异常,大概信息如下:org.apache.poi.poifs.filesystem.OfficeXmlFileException: The supplied data appears to be in the Office 2007+ XML. You are calling the part of POI that deals with OLE2 Office Documents. You need to call a different part of POI to process this data (eg XSSF instead of HSSF);

异常指出我们用了Office2007以上的版本(包含2007),要我们用XSSF来代替HSSF。

于是我们开始替换我们的代码,用XSSF代替HSSF。可是我们却意外的发现poi.jar包中,并不包含XSSF,那么XSSF到底从哪来的呢?百度一下发现,他们来自不同的星球:

(1)XSSFWorkbook:poi-ooxml-.jar                           org.apache.poi.xssf.usermodel.XSSFWorkbook
(2)HSSFWorkbook:poi.jar                                      org.apache.poi.hssf.usermodel.HSSFWorkbook

查看源码:

POI 读取 Excel 文件(2003版本与2007版本的差异之处)_第1张图片

POI 读取 Excel 文件(2003版本与2007版本的差异之处)_第2张图片

多么的巧合啊!HSSFWorkbook 和 XSSFWorkbook 都实现了 Workbook 接口!

所以思路就来了,我们用时引入这两种jar包,在判断出Excel的版本号,根据Excel版本的不同来用HSSFWorkbook 或者XSSFWorkbook 的实现 Workbook。下面就直接上代码吧!

POI的版本号:

 

3.12

	org.apache.poi
	poi
	${poi.version}


	org.apache.poi
	poi-ooxml
	${poi.version}

读取Excel文件的Java类:

 

 

/**
 * @package :com.changhongit.andy.util
* @author :wanglongjie
* @createDate :2015年8月31日下午1:37:32
*/ package com.changhongit.andy.util; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.poi.hssf.usermodel.HSSFDateUtil; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.poifs.filesystem.POIFSFileSystem; 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; /** * @package :com.changhongit.andy.util
* @file :ExcelReader.java
* @describe :读取 Excel 文件
* @author :wanglongjie
* @createDate :2015年8月31日下午1:37:32
* @updater :
* @updateDate :
* @updateContent :
*/ public class ExcelReader { static private Workbook wb; static private Sheet sheet; static private Row row; /** * * @method :readExcelTitle
* @describe :读取 Excel 文件
* @author :wanglongjie
* @createDate :2015年8月31日下午2:41:25
* @param fileName * :Excel 文件路径 * @return String[] */ public static String[] readExcelTitle(String fileName) { InputStream is; try { is = new FileInputStream(fileName); String postfix = fileName.substring(fileName.lastIndexOf("."), fileName.length()); if (postfix.equals(".xls")) { // 针对 2003 Excel 文件 wb = new HSSFWorkbook(new POIFSFileSystem(is)); sheet = wb.getSheetAt(0); } else { // 针对2007 Excel 文件 wb = new XSSFWorkbook(is); sheet = wb.getSheetAt(0); } } catch (IOException e) { e.printStackTrace(); } sheet = wb.getSheetAt(0); row = sheet.getRow(0);// 获取第一行(约定第一行是标题行) int colNum = row.getPhysicalNumberOfCells();// 获取行的列数 String[] titles = new String[colNum]; for (int i = 0; i < titles.length; i++) { titles[i] = getCellFormatValue(row.getCell(i)); } return titles; } /** * * @method :readExcelContent
* @describe :读取 Excel 内容
* @author :wanglongjie
* @createDate :2015年8月31日下午3:12:06
* @param fileName * :Excel 文件路径 * @return List> */ public static List> readExcelContent(String fileName) { List> list = new ArrayList<>(); Map content = null; try { InputStream is; is = new FileInputStream(fileName); String postfix = fileName.substring(fileName.lastIndexOf("."), fileName.length()); if (postfix.equals(".xls")) { // 针对 2003 Excel 文件 wb = new HSSFWorkbook(new POIFSFileSystem(is)); sheet = wb.getSheetAt(0); } else { // 针对2007 Excel 文件 wb = new XSSFWorkbook(is); sheet = wb.getSheetAt(0); } } catch (IOException e) { e.printStackTrace(); } sheet = wb.getSheetAt(0); int rowNum = sheet.getLastRowNum();// 得到总行数 row = sheet.getRow(0); int colNum = row.getPhysicalNumberOfCells(); String titles[] = readExcelTitle(fileName); // 正文内容应该从第二行开始,第一行为表头的标题 for (int i = 1; i <= rowNum; i++) { int j = 0; row = sheet.getRow(i); content = new LinkedHashMap<>(); do { content.put(titles[j], getCellFormatValue(row.getCell(j)) .trim()); j++; } while (j < colNum); list.add(content); } return list; } /** * 根据Cell类型设置数据 * * @param cell * @return */ private static String getCellFormatValue(Cell cell) { String cellvalue = ""; if (cell != null) { // 判断当前Cell的Type switch (cell.getCellType()) { // 如果当前Cell的Type为NUMERIC case Cell.CELL_TYPE_NUMERIC: case Cell.CELL_TYPE_FORMULA: { // 判断当前的cell是否为Date if (HSSFDateUtil.isCellDateFormatted(cell)) { // 方法2:这样子的data格式是不带带时分秒的:2011-10-12 Date date = cell.getDateCellValue(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); cellvalue = sdf.format(date); } else { // 如果是纯数字取得当前Cell的数值 cellvalue = String.valueOf(cell.getNumericCellValue()); } break; } // 如果当前Cell的Type为STRIN case Cell.CELL_TYPE_STRING: // 取得当前的Cell字符串 cellvalue = cell.getRichStringCellValue().getString(); break; default: // 默认的Cell值 cellvalue = " "; } } else { cellvalue = ""; } return cellvalue; } public static void main(String[] args) { String file = "E://Andy/work/Tomcat 7.0/webapps/customer/WEB-INF/upload/客户收支配置.xlsx"; List> list = ExcelReader.readExcelContent(file); Map map = null; for (int i = 0; i < list.size(); i++) { map = list.get(i); Entry entry = null; for (Iterator> it = map.entrySet().iterator(); it .hasNext();) { entry = it.next(); System.out.println(entry.getKey() + "-->" + entry.getValue()); } System.out.println("............"); } } }

主要的思路就是,我们在定义成员变量时不在定义某一种实现类,而是定义成接口:

 

 static private Workbook wb;
 static private Sheet sheet;
 static private Row row;

然后根据上传文件的后缀名,判断是2003Excel还是2007Excel,再决定用不同的类实现成员变量的接口,从而达到代码既支持2003Excel有支持2007Excel:

            InputStream is = new FileInputStream(fileName);
            String postfix = fileName.substring(fileName.lastIndexOf("."),
                    fileName.length());
            if (postfix.equals(".xls")) {
                // 针对 2003 Excel 文件
                wb = new HSSFWorkbook(new POIFSFileSystem(is));
                sheet = wb.getSheetAt(0);
            } else {
                // 针对2007 Excel 文件
                wb = new XSSFWorkbook(is);
                sheet = wb.getSheetAt(0);
            }

最后纠结了半天的问题终于解决了,欧耶

已整理成完整项目,并进行了优化。看参考地址:

https://gitee.com/andy_longjie/exceltools   或者 https://github.com/youmulongjie/exceltools

转载于:https://my.oschina.net/andy1989/blog/499605

你可能感兴趣的:(POI 读取 Excel 文件(2003版本与2007版本的差异之处))