EasyExcel 使用记录

使用的是阿里的 EasyExcel ,在读的时候出现NPE错误,追究一下

使用 EasyExcel 写excel的时候 api 非常简单好用,而在读的时候却发现有一些bug。
maven依赖版本

		<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>1.1.2-beta5</version>
        </dependency>

1.1.2-beta5 是当前(2019年3月16日)最新版,然而却不是稳定版,其中1.0.0有稳定版,但官方的github的示例却是 测试版的(1.1.2-beta4),且对前版本兼容较差。在评论中也是bug百出,可见阿里开发这个组件的负责人已经停止维护了。

此篇仅记录该工具类的一个问题

读取文件路径 “F:/excelx.xlsx”
代码:

//从excel中读取
    public static List<Object> read(String excelName) throws IOException{
        if(StringUtils.isEmpty(excelName))
            return null;
        try( InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(excelName)) {
            // 解析每行结果在listener中处理
            return EasyExcelFactory.read(inputStream, new Sheet(1, 0));//该除为41行
        }
    }
java.lang.NullPointerException
	at com.alibaba.excel.support.ExcelTypeEnum.valueOf(ExcelTypeEnum.java:31)
	at com.alibaba.excel.ExcelReader.<init>(ExcelReader.java:94)
	at com.alibaba.excel.EasyExcelFactory.read(EasyExcelFactory.java:30)
	at com.msgc.utils.excel.ExcelUtil.read(ExcelUtil.java:41)

发现是在调用用 read 的时候
一步一步翻源码看,源码在read前调用了 new ExcelReader。
而在该类的 init 方法中第一行调用了
ExcelTypeEnum excelTypeEnum = ExcelTypeEnum.valueOf(in);
源码如下

public static ExcelTypeEnum valueOf(InputStream inputStream) {
        try {
            if (!inputStream.markSupported()) {//出错点
                return null;
            } else {
                FileMagic fileMagic = FileMagic.valueOf(inputStream);
                if (FileMagic.OLE2.equals(fileMagic)) {
                    return XLS;
                } else {
                    return FileMagic.OOXML.equals(fileMagic) ? XLSX : null;
                }
            }
        } catch (IOException var2) {
            throw new RuntimeException(var2);
        }
    }

(阅读发现阿里的EasyExcel其实是封装了 apache 的 poi ,稍微改了一些地方,让使用起来更加方便,却有一堆修不完的 bug,后来也停止维护了。)

根据堆栈信息,是inputStream.markSupported()方法报的错,点开是 jdk 的源码

/**
     * Tests if this input stream supports the <code>mark</code> and
     * <code>reset</code> methods. Whether or not <code>mark</code> and
     * <code>reset</code> are supported is an invariant property of a
     * particular input stream instance. The <code>markSupported</code> method
     * of <code>InputStream</code> returns <code>false</code>.
     *
     * @return  <code>true</code> if this stream instance supports the mark
     *          and reset methods; <code>false</code> otherwise.
     * @see     java.io.InputStream#mark(int)
     * @see     java.io.InputStream#reset()
     */
    public boolean markSupported() {
        return false;
    }

翻译过来大概是说这是个标志方法,用来检测输入流是否支持标记和重置方法,jdk 的输入输出流采用了装饰者模式,该处是写死的也不为过。

而我是拷贝了官方给的例子。

总结

使用EasyExcel 读的时候最好多看看源码,不看源码很容易出问题。
本文出现问题解决方案:

//从excel中读取
    public static List<Object> read(String excelName) throws IOException{
        try(BufferedInputStream is = new BufferedInputStream(new FileInputStream(excelName))) {
            if(is == null)
                return null;
            return EasyExcelFactory.read(is, new Sheet(1, 0));
        }
    }

装饰器包装一下,而不用示例给的.
Thread.currentThread().getContextClassLoader().getResourceAsStream("" + fileName);

猜你喜欢

转载自blog.csdn.net/qq_35425070/article/details/88594136