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.hasPOIFSHeaderPOIFSFileSystem.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
            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

目录
相关文章
|
5月前
|
Java API Apache
Java编程如何读取Word文档里的Excel表格,并在保存文本内容时保留表格的样式?
【10月更文挑战第29天】Java编程如何读取Word文档里的Excel表格,并在保存文本内容时保留表格的样式?
355 5
|
4月前
|
人工智能 自然语言处理 Java
FastExcel:开源的 JAVA 解析 Excel 工具,集成 AI 通过自然语言处理 Excel 文件,完全兼容 EasyExcel
FastExcel 是一款基于 Java 的高性能 Excel 处理工具,专注于优化大规模数据处理,提供简洁易用的 API 和流式操作能力,支持从 EasyExcel 无缝迁移。
523 9
FastExcel:开源的 JAVA 解析 Excel 工具,集成 AI 通过自然语言处理 Excel 文件,完全兼容 EasyExcel
|
4月前
|
存储 Java 数据挖掘
Java 8 新特性之 Stream API:函数式编程风格的数据处理范式
Java 8 引入的 Stream API 提供了一种新的数据处理方式,支持函数式编程风格,能够高效、简洁地处理集合数据,实现过滤、映射、聚合等操作。
151 6
|
4月前
|
Java API 开发者
Java中的Lambda表达式与Stream API的协同作用
在本文中,我们将探讨Java 8引入的Lambda表达式和Stream API如何改变我们处理集合和数组的方式。Lambda表达式提供了一种简洁的方法来表达代码块,而Stream API则允许我们对数据流进行高级操作,如过滤、映射和归约。通过结合使用这两种技术,我们可以以声明式的方式编写更简洁、更易于理解和维护的代码。本文将介绍Lambda表达式和Stream API的基本概念,并通过示例展示它们在实际项目中的应用。
|
5月前
|
Java BI API
Java Excel报表生成:JXLS库的高效应用
在Java应用开发中,经常需要将数据导出到Excel文件中,以便于数据的分析和共享。JXLS库是一个强大的工具,它基于Apache POI,提供了一种简单而高效的方式来生成Excel报表。本文将详细介绍JXLS库的使用方法和技巧,帮助你快速掌握Java中的Excel导出功能。
162 6
|
4月前
|
Rust 安全 Java
Java Stream 使用指南
本文介绍了Java中Stream流的使用方法,包括如何创建Stream流、中间操作(如map、filter、sorted等)和终结操作(如collect、forEach等)。此外,还讲解了并行流的概念及其可能带来的线程安全问题,并给出了示例代码。
300 0
|
6月前
|
Java 流计算
Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!
Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!
81 1
Flink-03 Flink Java 3分钟上手 Stream 给 Flink-02 DataStreamSource Socket写一个测试的工具!
|
6月前
|
Java Shell 流计算
Flink-02 Flink Java 3分钟上手 Stream SingleOutputStreamOpe ExecutionEnvironment DataSet FlatMapFunction
Flink-02 Flink Java 3分钟上手 Stream SingleOutputStreamOpe ExecutionEnvironment DataSet FlatMapFunction
57 1
Flink-02 Flink Java 3分钟上手 Stream SingleOutputStreamOpe ExecutionEnvironment DataSet FlatMapFunction
|
5月前
|
Java API Apache
|
5月前
|
存储 Java API
Java实现导出多个excel表打包到zip文件中,供客户端另存为窗口下载
Java实现导出多个excel表打包到zip文件中,供客户端另存为窗口下载
390 4