wangguanquan / eec

A fast and lower memory excel write/read tool.一个非POI底层,支持流式处理的高效且超低内存的Excel读写工具
https://github.com/wangguanquan/eec/wiki
Apache License 2.0
187 stars 54 forks source link

sheet.rows()方法获取row报NPE #208

Closed RexH0 closed 3 years ago

RexH0 commented 3 years ago

image

eec 版本 0.4.11

RexH0 commented 3 years ago

111111.xlsx 见附件文档

wangguanquan commented 3 years ago

Row是内存共享的,不可以直接转List,你可以将其转为对象,或者直接流式处理。

    @Test public void test() {
        try (ExcelReader reader = ExcelReader.read(Paths.get("./Downloads/111111.xlsx"))) {
            reader.sheets().flatMap(Sheet::rows).forEach(System.out::println);

            reader.sheet(0).reset();

            List<O> list = reader.sheet(0).rows().filter(row -> row.getRowNumber() > 16).map(row -> row.to(O.class)).filter(Objects::nonNull).collect(Collectors.toList());

            list.forEach(System.out::println);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static class O {
        @ExcelColumn("亚马逊FBA子单号/箱唛号(必填)(FBA号正确19位)")
        private String fbaNo;

        @ExcelColumn("Reference ID(亚马逊追踪编码)")
        private String refId;

        @ExcelColumn("中文品名(必填)")
        private String nameCn;

        @Override
        public String toString() {
            return "fbaNo: " + fbaNo + ", refId: " + refId + ", nameCn: " + nameCn;
        }
    }
wangguanquan commented 3 years ago

如果不知道从哪一行开始转对象可以像下面这样判断

    AtomicBoolean begin = new AtomicBoolean(false);
    List<O> list = reader.sheet(0).rows().filter(row -> {
        if (begin.get()) return true;
        if ("亚马逊FBA子单号/箱唛号(必填)(FBA号正确19位)".equals(row.getString(0))) {
            begin.set(true);
            return true;
        }
        return false;
    }).map(row -> row.to(O.class)).filter(Objects::nonNull).collect(Collectors.toList());
wangguanquan commented 3 years ago

不知道我有没有表述清楚,EEC以迭代模式设计读文件,当真正需要某行数据的时候才会去解析,保证最小的使用内存,这也就是为什么EEC能够仅用几M的内存就可以读取GB级别的文件,无认是xlsx还是xls均是这种设计模式。

上面的语句List<Row> rows = sheet.rows().collect(Collectors.toList()); 只有最后一行数据,Row对象也只有一个引用。

RexH0 commented 3 years ago

业务上无法转成对象 因为导入的模板不固定,所以只能把每一行的数据取出来放在list中

RexH0 commented 3 years ago

image 不知道是不是我的excel有问题 at org.ttzero.excel.reader.XMLSheet.nextRow(XMLSheet.java:358)流式处理的时候这行就报错了

wangguanquan commented 3 years ago

能将代码贴一下吗

RexH0 commented 3 years ago

package org.ttzero.excel.reader;

import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.time.DateFormatUtils; import org.ttzero.excel.util.FileUtil;

import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.*; import java.util.stream.Collectors;

/**

}

RexH0 commented 3 years ago

image 这个代码线上已经用了几个月了,大部分excel都没有问题,少部分excel 比如我发给你那个 sheet.rows()这里就报错

wangguanquan commented 3 years ago

请将sheet.rows()改为sheet.load().rows(),延迟加载的缘故,调用load方法会获取头信息。

可以看一下ExcelReader源码

    public Stream<Sheet> sheets() {
        Iterator<Sheet> iter = new Iterator<Sheet>() {
            int n = 0;

            @Override
            public boolean hasNext() {
                return n < sheets.length;
            }

            @Override
            public Sheet next() {
                try {
                    // test and load sheet data
                    return sheets[n++].load();  // <---重点在这里
                } catch (IOException e) {
                    throw new UncheckedIOException(e);
                }
            }
        };
        return StreamSupport.stream(Spliterators.spliterator(iter, sheets.length
            , Spliterator.ORDERED | Spliterator.NONNULL), false);
    }
wangguanquan commented 3 years ago

建议将版本更新到v0.4.13,从这个版本开始支持xls格式的图片读取,并且Picture类也改为public了,不需要把代码放到org.ttzero包下。

RexH0 commented 3 years ago

好 我试下 , thansk!!!