文档章节

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

Andy市民
 Andy市民
发布于 2015/08/31 16:41
字数 1248
阅读 2531
收藏 0

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

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

查看源码:

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

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

POI的版本号:

 

<poi.version>3.12</poi.version>
<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>poi</artifactId>
	<version>${poi.version}</version>
</dependency>
<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>poi-ooxml</artifactId>
	<version>${poi.version}</version>
</dependency>

读取Excel文件的Java类:

 

 

/**
 * @package :com.changhongit.andy.util<br>
 * @author :wanglongjie<br>
 * @createDate :2015年8月31日下午1:37:32<br>
 */
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<br>
 * @file :ExcelReader.java<br>
 * @describe :读取 Excel 文件<br>
 * @author :wanglongjie<br>
 * @createDate :2015年8月31日下午1:37:32<br>
 * @updater :<br>
 * @updateDate :<br>
 * @updateContent :<br>
 */
public class ExcelReader {
	static private Workbook wb;
	static private Sheet sheet;
	static private Row row;

	/**
	 * 
	 * @method :readExcelTitle<br>
	 * @describe :读取 Excel 文件<br>
	 * @author :wanglongjie<br>
	 * @createDate :2015年8月31日下午2:41:25 <br>
	 * @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<br>
	 * @describe :读取 Excel 内容<br>
	 * @author :wanglongjie<br>
	 * @createDate :2015年8月31日下午3:12:06 <br>
	 * @param fileName
	 *            :Excel 文件路径
	 * @return List<Map<String,String>>
	 */
	public static List<Map<String, String>> readExcelContent(String fileName) {
		List<Map<String, String>> list = new ArrayList<>();
		Map<String, String> 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<Map<String, String>> list = ExcelReader.readExcelContent(file);
		Map<String, String> map = null;
		for (int i = 0; i < list.size(); i++) {
			map = list.get(i);
			Entry<String, String> entry = null;
			for (Iterator<Entry<String, String>> 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

© 著作权归作者所有

Andy市民
粉丝 11
博文 37
码字总数 32801
作品 0
房山
程序员
私信 提问
Java之POI读取Excel的解决兼容性问题

在Java中,使用POI来进行excel的读取和解析是常用的一种做法;在office的excel中存在2007,2003两种不同的格式,通常情况下是以xls/xlsx的不同后缀来区分的,但用户可能不知道这个区别,所以会...

灌南高手No1
02/22
0
0
POI - 读取Excel2003、Excel2007或更高级的兼容性问题

我们使用POI中的HSSFWorkbook来读取Excel数据。 上边代码,读取Excel2003(xls)的文件没问题,但是一旦读取的是Excel2007(xlsx)的文件,就会报异常:“The supplied data appears to be i...

技术小美
2017/11/14
0
0
java读取excel问题的总结

1.技术方案确定,由于excel目前有两种格式,一个是2003的xls,一个是2007之后的xlsx.所选的方案必须是同事能够处理这两种格式的excel的。 目前比较流行的两个解决方案,一个是Apache的jxl 另...

疯狂的兔子
2016/11/10
95
0
JAVA用POI读取和创建2003和2007版本Excel完美示例

import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.text.DecimalF......

java牛
2015/10/26
0
0
在云端-看世间变幻/fluentexcel

##fluentexcel 简介 fluentexcel基于POI,旨在改进 excel 生成时的编码体验, 借鉴 fluent api 思想开发方便易用,同时书写方便的 excel 的 api。 更重要的是 fluentexcel 可以将一个 excel 20...

在云端-看世间变幻
2015/02/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

自定义ApiBoot Logging链路以及单元ID生成策略

ApiBoot Logging会为每一个请求都对应创建链路编号(TraceID)以及单元编号(SpanID),用于归类每一次请求日志,通过一个链路下日志单元的Parent SpanID可以进行上下级关系的梳理。 前文回顾...

恒宇少年
18分钟前
6
0
浅谈 Application 和 activity

对于 在 Application初始化一些变量,为什么不可以放在activity 或者其他的组件里呢? 这里就根据个人的理解来讲述一下,欢迎补充指正。 首先 activity 是以栈的形式出现,一个app应用会有多...

MrLins
18分钟前
5
0
Allegro的脚本文件内容里都有哪些

小伙伴们在使用Allegro的时候是否经常用到脚本文件夹呢?scr的用法其实可真不简单。。。 首先脚本文件的运行模式就存在很多种,比如不提示错误信息,不弹出确认对画框(这样很有利于我们执行...

demyar
19分钟前
12
0
微信升级外链管理规范,「砍一刀帮我加速」要被禁止了

原创: 蒋鸿昌 首发:「知晓程序」公众号 - 最好的微信新商业媒体 几天前,知名互联网评论人阑夕模仿皮尤研究中心(Pew Research Center)在美国做的互联网通识调查问卷,做了一份中文版问卷...

知晓云
20分钟前
8
0
CentOS 7接投影仪

我将一台安装着CentOS 7图形界面的惠普笔记本电脑当桌面使用。最近,想要连接投影仪时却遇到了问题。笔记本有一个HDMI接口。我买了一个HDMI---->VGA的转接线,连上笔记本电脑后,屏幕一直在闪...

大别阿郎
23分钟前
7
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部