Java POI重复读取excel:stream closed,回退流PushbackInputStream解决
Java POI读取Excel有两种文件格式,2003和2007以上的,需要通过不同的api进行读取,于是写了下面的工具类。
public class ExcelReadUtil { private static Logger log = LoggerFactory.getLogger(ExcelReadKit.class); /** * * @param fis * 输入的文件流 * @param sheetIndex * 第x个sheet * @return */ public void readExcel(InputStream fis, int sheetIndex) { try { Sheet sheet = null; Workbook wb = null; try { // 利用poi读取excel文件流,2003版本 POIFSFileSystem fs = new POIFSFileSystem(fis); wb = new HSSFWorkbook(fs); // 读取excel工作簿 sheet = wb.getSheetAt(sheetIndex); // 读取excel的sheet,0表示读取第一个 } catch (Exception e) { // 利用poi读取excel文件流,2007及以上版本 wb = new XSSFWorkbook(fis); // 读取excel工作簿 sheet = wb.getSheetAt(sheetIndex); // 读取excel的sheet,0表示读取第一个 } //读取操作省略。。。 wb.cloneSheet(sheetIndex); fis.close(); } catch (Exception e) { log.error("读取Excel文件流时出错:", e); } finally { if (fis != null) { try { fis.close(); } catch (Exception e) { } } } } }
先读取2003(.xls)
版本的,如果异常就读取2007(.xlsx)
版本的,看起来没什么问题,但是实际使用中,当读取xlsx文件的时候会stream closed
报错,这是为什么呢?原来当读取了一次文件流的异常之后,运行到wb = new XSSFWorkbook(fis); // 读取excel工作簿
的时候,输入流已经被关闭了。
怎么解决这个InputStream
被关闭的问题呢?使用前用PushbackInputStream
包装,读取前先POIFSFileSystem.hasPOIFSHeader
和POIFSFileSystem.hasPOIFSHeader
方法读取流的头判断文件格式
修改如下:
public class ExcelReadUtil { private static Logger log = LoggerFactory.getLogger(ExcelReadKit.class); /** * * @param fis * 输入的文件流 * @param sheetIndex * 第x个sheet * @return */ public void readExcel(InputStream fis, int sheetIndex) { try { Sheet sheet = null; Workbook wb = null; // 不加报错:java.io.IOException: mark/reset not supported //PushbackInputStream参考:https://my.oschina.net/fhd/blog/345011 if (!fis.markSupported()) { fis = new PushbackInputStream(fis, 8); } /** * 只能通过这种方式判断版本,使用如果通过 * try catch捕获异常方式先读取了一次,流会被关闭,后面就读取不到了 */ //2003版 if (POIFSFileSystem.hasPOIFSHeader(fis)) { // 读取excel工作簿 wb = new HSSFWorkbook(fis); } //2007版 else if (POIXMLDocument.hasOOXMLHeader(fis)) { //OPCPackage.open(fis)取得一个文件的读写权限 wb = new XSSFWorkbook(OPCPackage.open(fis)); } //读取操作省略。。。 wb.cloneSheet(sheetIndex); fis.close(); } catch (Exception e) { log.error("读取Excel文件流时出错:", e); } finally { if (fis != null) { try { fis.close(); } catch (Exception e) { } } } } }
使用工具类,此时读取两种格式的文件都没有问题了
public class ExcelReaderTest { @Test public void readData() throws IOException, ParseException { File file = new File("D:\\test.xlsx"); ExcelReadUtil excelReader = new ExcelReadUtil(); //只读取第一个sheet页 excelReader.readExcel(new FileInputStream(file), 0); //... } }
具体PushbackInputStream介绍参考:https://my.oschina.net/fhd/blog/345011
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
Shiro和SpringBoot简单集成
Shiro是一种简单的安全框架,可以用来处理系统的登录和权限问题。 本篇记录一下Spring Boot和Shiro集成,并使用Jwt Token进行无状态登录的简单例子。参考Demo地址,此Demo适合用于SpringBoot小型项目的快速开发。 环境 SpringBoot 版本 1.5.15.RELEASE 不建议使用2.x版本的Springboot,与1.x相比很多地方代码有所改动,很麻烦。 Shiro 版本 1.4.0 IntelliJ IDEA jjwt 版本 0.9.0 lombok(可选)精简代码 思路 使用Jwt Token实现无状态登录 平时用户登录后,服务器将会把用户信息存储到Session里,在用户数量很大的时候,服务器负担会很大。而使用token方式登录,服务器不存储用户信息,而是将其加密后生成token发送给请求方,请求方在请求需要权限的资源时,将token带上,服务器解析token即可知道登录用户的信息。 服务器自动刷新token token需要刷新。对于活跃的用户,服务器自动完成刷新token;对于长期不活跃的用户,服务器通过配置的 token有效期 来检查...
- 下一篇
线程中断以及线程中断引发的那些问题
什么是线程中断? 在我们的Java程序中其实有不止一条执行线程,只有当所有的线程都运行结束的时候,这个Java程序才算运行结束。 官方的话给你描述一下:当所有的非守护线程运行结束时,或者其中一个线程调用了System.exit()方法时,这个Java程序才能运行结束。 线程中断的应用场景 我们先来举一个例子,比如我们现在在下载一个500多M的大片,我们点击开始下载,那个这个时候就等于开启了一个线程去下载我们的文件,然而这个时候我们的网速不是很给力,几十KB的在这跑,作为一个年轻人我是等不了了,我不下来,那么这个时候我们第一个操作就是结束掉这个下载文件的操作,其实更接近程序的来说,这个时候我们就需要把这个线程给中断了。 我们接下来写一下这个下载的代码,看一下如何中断一个线程,这里我已经默认你们已经掌握了如何创建一个线程了,这段程序我们模拟下载,最开始获取系统时间,然后进入循环每次获取系统时间,如果时间超过10秒我们就中断线程,不在继续下载,下载速度时每秒1M: public void run() { int number = 0; // 记录程序开始的时间 Long start = Sy...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS关闭SELinux安全模块
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- Hadoop3单机部署,实现最简伪集群
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- CentOS6,CentOS7官方镜像安装Oracle11G
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS8编译安装MySQL8.0.19
- CentOS6,7,8上安装Nginx,支持https2.0的开启