alibaba / easyexcel

快速、简洁、解决大文件内存溢出的java处理Excel工具
https://easyexcel.opensource.alibaba.com
Apache License 2.0
32.35k stars 7.52k forks source link

在读取日期类型得数据,和数值类型的数据时,日期会偶现读成1970-01-01,数值则是乱码得情况 #3970

Open syc824951 opened 2 months ago

syc824951 commented 2 months ago

建议先去看文档

快速开始常见问题

触发场景描述

上传文件。并读取时,在读到日期类型时 比如 创建时间 实际数据为:1999-01-01 11:22:33 但是在程序读出来时会变成1970-01-01 00:00:00 还有在读取数值类型时,原数据为:119944, 在读取后数据为 示例:0(0xwhwh),实际类似。

触发Bug的代码

     ReadSheet readSheet = EasyExcel
                    .readSheet(sheetNum)
                    .registerReadListener(dataListener)
                    .build();
            excelReader.read(readSheet);
            excelReadDto.setDataList(dataListener.getDataList());

提示的异常或者没有达到的效果

大家尽量把问题一次性描述清楚,然后贴上全部异常,这样方便把问题一次性解决掉。 至少大家要符合一个原则就是,能让其他人复现出这个问题,如果无法复现,肯定无法解决。

psxjoy commented 2 months ago

same question link #3793 . Please add config use1904windowing(true)

syc824951 commented 2 months ago

目前这个情况与上述问题不是一个问题,

企业微信截图_17253475022332

现在是将上图数据 会识别为1970/01/01 这种情况。还有一种情况忘说了,在wps中点击该时间框会转变为数值类型,如图:

jiaoyi

这种数据读取会丢失左上方公式框内的精度。

daihaipeng commented 2 months ago

我也出现日期读取出现错误情况,在程序读取1999/10/10 12:00:00 时候,大部分情况都是正常将数值转成日期,会偶现出现读取出来是数值36443.5,不知道是不是DateUtils中的ThreadLocal变量引起,望解答!

gongxuanzhang commented 2 months ago

请提供完整代码或仓库链接

syc824951 commented 2 months ago

image image image

gongxuanzhang commented 2 months ago

我无法通过你的贴图复现你的问题,请提供可以复现的代码和excel

syc824951 commented 2 months ago

服务器为arm64架构 日期出问题文件为: 日期问题文件.xlsx 丢失精度问题文件为:这里数据是再wps中双击交易时间列,他会自动转为数值,读取时会丢失公式框内精度。 丢失精度数据问题.xlsx 金额读取乱码文件:其中标黄的1.66为容易出问题地方 金额读取乱码文件.xlsx 读取时日志截图如下:

企业微信截图_17254299778983
gongxuanzhang commented 2 months ago

你可以提供一份直接复现问题的代码或仓库链接吗? 你的问题已经描述清楚了,我需要一份能复现的代码而不是各种贴图

syc824951 commented 2 months ago
package com.chinatelecom.business.datahandle.listener;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.chinatelecom.business.datahandle.domain.dto.ExcelReadDto;
import lombok.Data;
import org.springframework.util.CollectionUtils;

import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Test {

    public static void main(String[] args) {
        List<ExcelReadDto> list = new ArrayList<>();
        try (InputStream fis = new URL("file:///E:\\work\\测试500问题\\空文件.xlsx").openStream()){
            ExcelReader excelReader = EasyExcel.read(fis).build();
            List<ReadSheet> readSheets = excelReader.excelExecutor().sheetList();
            for (int i = 0; i < readSheets.size(); i++) {
                ReadSheet readSheet = readSheets.get(i);
                ExcelReadDto excelReadDto = new ExcelReadDto();
                excelReadDto.setSheetName(readSheet.getSheetName());
                list.add(readLimitExcel(excelReadDto, "空文件", 30, 20, readSheets.size(), i, excelReader));
            }
            System.out.println(readSheets);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public static ExcelReadDto readLimitExcel(ExcelReadDto excelReadDto, String fileName, Integer limitColSize, Integer limitRowSize, int sheetTotal, int sheetNum, ExcelReader excelReader) {

        LimitExcelReadListener dataListener = null;
        // 读取sheet页数目

        //读取文件数据
        try {
            //声明读取所需FileInputStream
            excelReadDto.setSheetTotal(sheetTotal);
            excelReadDto.setSheetNum(sheetNum + 1);
            excelReadDto.setFileName(fileName);

            dataListener = new LimitExcelReadListener(limitColSize, limitRowSize);

            //初始化一个监听器
            ReadSheet readSheet = EasyExcel
                    .readSheet(sheetNum)
                    .registerReadListener(dataListener)
                    .build();
            excelReader.read(readSheet);
            excelReadDto.setDataList(dataListener.getDataList());
            excelReader.finish();
        } catch (Exception e) {
            throw new RuntimeException();
        }
        return excelReadDto;
    }

    @Data
    static class LimitExcelReadListener extends AnalysisEventListener<Map<Integer, String>> {
        // 定义变量,分别表示限制列数和行数
        private Integer limitColSize;
        private Integer limitRowSize;
        private int sheetCount = 0;
        /**
         * 行数
         */
        private int num;

        // 定义变量,存储表头信息和表数据
        private List<Map<Integer, String>> headList = new ArrayList<>();
        private List<Map<Integer, String>> dataList = new ArrayList<>();

        // 构造函数
        public LimitExcelReadListener() {

        }

        // 带参构造函数,直接赋值限制行列
        public LimitExcelReadListener(Integer limitColSize, Integer limitRowSize) {
            this.limitColSize = limitColSize;
            this.limitRowSize = limitRowSize;
        }

        /**
         * 工具方法,根据传入的列限制来保留数据,也就是只取前几个Key,如果有需求,可以自己添加KeySet排序之后再取,我这里没这个需求
         *
         * @param oldMap 未限制列前的Map
         * @return 限制列后的Map
         */
        private Map<Integer, String> getLimitColMap(Map<Integer, String> oldMap) {
            Integer size = oldMap.keySet().size();
            Map<Integer, String> newMap = new HashMap<>();
            for (int i = 0; i < (size >= this.limitColSize ? this.limitColSize : size); i++) {
                //TODO 在这里获取时  就能看到乱码情况
                newMap.put(i, oldMap.get(i));
            }
            return newMap;
        }

        @Override
        public void invoke(Map<Integer, String> integerStringMap, AnalysisContext analysisContext) {

            // 判断行数已达到限制行数,抛出ExcelAnalysisException
            if (dataList.size() < this.limitRowSize) {
                Map<Integer, String> newMap = this.getLimitColMap(integerStringMap);

                dataList.add(newMap);
                if (dataList.size()>2){
                    if (!CollectionUtils.isEmpty(dataList)){
                        if (dataList.size() == 3){
                            System.out.println(dataList.get(0));
                            System.out.println(dataList.get(1));
                            System.out.println(dataList.get(2));
                        }

                    }
                }

                //            throw new ExcelAnalysisException(this.limitRowSize + "行" + this.limitColSize + "列读取完成");
            }
        }

        @Override
        public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
            // 获取限制列之后的表头Map,并存入headList
            Map<Integer, String> newMap = this.getLimitColMap(headMap);
            dataList.add(newMap);

            sheetCount++;
        }

        /**
         * 所有数据解析完成了 都会来调用
         *
         * @param context EasyExcel上下文
         */
        @Override
        public void doAfterAllAnalysed(AnalysisContext context) {

        }

    }

}

以上 是目前我整理出来的代码。

syc824951 commented 2 months ago

更新一下 这部分代码实在异步中进行的。 示例:ExecutorService executorService = Executors.newFixedThreadPool(10); executorService.submit(()->{ List<ExcelReadDto> list = new ArrayList<>(); try (InputStream fis = new URL("file:///E:\\work\\测试500问题\\空文件.xlsx").openStream()){ ExcelReader excelReader = EasyExcel.read(fis).build(); List<ReadSheet> readSheets = excelReader.excelExecutor().sheetList(); for (int i = 0; i < readSheets.size(); i++) { ReadSheet readSheet = readSheets.get(i); ExcelReadDto excelReadDto = new ExcelReadDto(); excelReadDto.setSheetName(readSheet.getSheetName()); list.add(readLimitExcel(excelReadDto, "空文件", 30, 20, readSheets.size(), i, excelReader)); } System.out.println(readSheets); } catch (Exception e) { e.printStackTrace(); } });

psxjoy commented 2 months ago

Hi, after reviewing the comments on this issue, I believe it would be most helpful to provide a runnable, minimal reproducible demo. If possible, making it a Maven project would enable others to get involved more easily.

Hi,我观察了这个issue的评论。我觉得最好提供一个可运行的、最小可复现demo。如果可以的话,最好是一个maven项目。这样能够让其他人更好的参与进来。