• EasyExcel——读Excel


    easyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。
    64M内存1分钟内读取75M(46W行25列)的Excel(当然还有急速模式能更快,但是内存占用会在100M多一点)
    可有效避免OOM。
    致敬阿里:

    ---参照官方文档进行编辑,主要记录了工作中用到的,用的少的就没有记录
    ---官方文档 : https://www.yuque.com/easyexcel
    ---官方github : https://github.com/alibaba/easyexcel

    操作实体类

    @Data
    public class DemoData {
        @ExcelProperty("字符串标题")
        private String stringData;
        @ExcelProperty(value = "数字标题")
        private Integer  integerData;
        @DateTimeFormat("yyyy年MM月dd日HH时mm分ss秒")
        @ExcelProperty("日期标题")
        private Date  dateData;
        @NumberFormat("#.##%")
        @ExcelProperty("浮点型标题")
        private Double   dounleData;
    }
    

    监听器类

    //DemoDataListener 不能被spring管理,要每次读取excel都要new,因此注入其他类的时候需要通过构造方法进行,而不是通过容器
    public class DemoDataListener  extends AnalysisEventListener<DemoData> {
        private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class);
        /**
         * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
         */
        private DemoDAO demoDAO;
        public DemoDataListener() {
            // 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数
            demoDAO = new DemoDAO();
        }
        /**
         * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
         * @param demoDAO
         */
        public DemoDataListener(DemoDAO demoDAO) {
            this.demoDAO = demoDAO;
        }
        /**
         * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
         */
        private static final int BATCH_COUNT = 5;
        List<DemoData> list = new ArrayList<DemoData>();
        /*
         *  每解析一条数据就会来调用
         */
        @Override
        public void invoke(DemoData demoData, AnalysisContext analysisContext) {
            LOGGER.info("解析到一条数据:{}", JSON.toJSONString(demoData));
            //根据demoData对数据进行校验
            list.add(demoData);
            // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
            if (list.size() >= BATCH_COUNT) {
                saveData();
                // 存储完成清理 list
                list.clear();
            }
        }
        @Override
        public void doAfterAllAnalysed(AnalysisContext analysisContext) {
            // 这里也要保存数据,确保最后遗留的数据也存储到数据库
            saveData();
            LOGGER.info("所有数据解析完成!");
        }
        /**
         * 加上存储数据库
         */
        private void saveData() {
            LOGGER.info("{}条数据,开始存储数据库!", list.size());
            demoDAO.save(list);
            LOGGER.info("存储数据库成功!");
        }
    
    }
    

    dao层(逗你玩~~)

    /**
     * 假设这个是你的DAO存储。当然还要这个类让spring管理,当然你不用需要存储,也不需要这个类。
     **/
    public class DemoDAO {
        public void save(List<DemoData> list) {
            // 如果是mybatis,尽量别直接调用多次insert,自己写一个mapper里面新增一个方法batchInsert,所有数据一次性插入
        }
    }
    

    读示例

            String fileName = "c://***";
            EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead(); 
    
    2020-04-13 19:26:37.109  INFO 17972 --- [           main] com.lh.easyexcel.util.DemoDataListener   : 解析到一条数据:{}
    2020-04-13 19:26:37.111  INFO 17972 --- [           main] com.lh.easyexcel.util.DemoDataListener   : 解析到一条数据:{}
    2020-04-13 19:26:37.111  INFO 17972 --- [           main] com.lh.easyexcel.util.DemoDataListener   : 解析到一条数据:{}
    2020-04-13 19:26:37.112  INFO 17972 --- [           main] com.lh.easyexcel.util.DemoDataListener   : 解析到一条数据:{}
    2020-04-13 19:26:37.112  INFO 17972 --- [           main] com.lh.easyexcel.util.DemoDataListener   : 解析到一条数据:{}
    2020-04-13 19:26:37.112  INFO 17972 --- [           main] com.lh.easyexcel.util.DemoDataListener   : 5条数据,开始存储数据库!
    2020-04-13 19:26:37.112  INFO 17972 --- [           main] com.lh.easyexcel.util.DemoDataListener   : 存储数据库成功!
    2020-04-13 19:26:37.113  INFO 17972 --- [           main] com.lh.easyexcel.util.DemoDataListener   : 解析到一条数据:{}
    2020-04-13 19:26:37.113  INFO 17972 --- [           main] com.lh.easyexcel.util.DemoDataListener   : 解析到一条数据:{}
    2020-04-13 19:26:37.113  INFO 17972 --- [           main] com.lh.easyexcel.util.DemoDataListener   : 解析到一条数据:{}
    2020-04-13 19:26:37.114  INFO 17972 --- [           main] com.lh.easyexcel.util.DemoDataListener   : 解析到一条数据:{}
    2020-04-13 19:26:37.114  INFO 17972 --- [           main] com.lh.easyexcel.util.DemoDataListener   : 解析到一条数据:{}
    2020-04-13 19:26:37.114  INFO 17972 --- [           main] com.lh.easyexcel.util.DemoDataListener   : 5条数据,开始存储数据库!
    2020-04-13 19:26:37.114  INFO 17972 --- [           main] com.lh.easyexcel.util.DemoDataListener   : 存储数据库成功!
    2020-04-13 19:26:37.114  INFO 17972 --- [           main] com.lh.easyexcel.util.DemoDataListener   : 解析到一条数据:{}
    2020-04-13 19:26:37.115  INFO 17972 --- [           main] com.lh.easyexcel.util.DemoDataListener   : 1条数据,开始存储数据库!
    2020-04-13 19:26:37.115  INFO 17972 --- [           main] com.lh.easyexcel.util.DemoDataListener   : 存储数据库成功!
    2020-04-13 19:26:37.115  INFO 17972 --- [           main] com.lh.easyexcel.util.DemoDataListener   : 所有数据解析完成!
    

    指定列的下标或者列名

        /**
         * 强制读取第三个 这里不建议 index 和 name 同时用,要么一个对象只用index,要么一个对象只用name去匹配
         */
        @ExcelProperty(index = 2)
        private Double doubleData;
        /**
         * 用名字去匹配,这里需要注意,如果名字重复,会导致只有一个字段读取到数据
         */
        @ExcelProperty("字符串标题")
        private String string;
        @ExcelProperty("日期标题")
        private Date date;
    

    读多个sheet

            String fileName = "c://***";
            // 读取全部sheet
            // 这里需要注意 DemoDataListener的doAfterAllAnalysed 会在每个sheet读取完毕后调用一次。然后所有sheet都会往同一个DemoDataListener里面写
            EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).doReadAll();
            // 读取部分sheet
            fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
            ExcelReader excelReader = EasyExcel.read(fileName).build();
            // 这里为了简单 所以注册了 同样的head 和Listener 自己使用功能必须不同的Listener
            ReadSheet readSheet1 =
                EasyExcel.readSheet(0).head(DemoData.class).registerReadListener(new DemoDataListener()).build();
            ReadSheet readSheet2 =
                EasyExcel.readSheet(1).head(DemoData.class).registerReadListener(new DemoDataListener()).build();
            // 这里注意 一定要把sheet1 sheet2 一起传进去,不然有个问题就是03版的excel 会读取多次,浪费性能
            excelReader.read(readSheet1, readSheet2);
            // 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的
            excelReader.finish();
    

    日期、数字或者自定义格式转换

        /**
         * 自定义 转换器,不管数据库传过来什么 。给他加上“自定义:”
         */
        @ExcelProperty(converter = CustomStringStringConverter.class)
        private String string;
        /**
         * 这里用string 去接日期才能格式化。我想接收年月日格式
         */
        @DateTimeFormat("yyyy年MM月dd日HH时mm分ss秒")
        private String date;
        /**
         * 我想接收百分比的数字
         */
        @NumberFormat("#.##%")
        private String doubleData;
    
    public class CustomStringStringConverter implements Converter<String> {
        @Override
        public Class supportJavaTypeKey() {
            return String.class;
        }
        @Override
        public CellDataTypeEnum supportExcelTypeKey() {
            return CellDataTypeEnum.STRING;
        }
        /**
         * 这里读的时候会调用
         *
         * @param cellData
         *            NotNull
         * @param contentProperty
         *            Nullable
         * @param globalConfiguration
         *            NotNull
         * @return
         */
        @Override
        public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
            GlobalConfiguration globalConfiguration) {
            return "自定义:" + cellData.getStringValue();
        }
        /**
         * 这里是写的时候会调用 不用管
         *
         * @param value
         *            NotNull
         * @param contentProperty
         *            Nullable
         * @param globalConfiguration
         *            NotNull
         * @return
         */
        @Override
        public CellData convertToExcelData(String value, ExcelContentProperty contentProperty,
            GlobalConfiguration globalConfiguration) {
            return new CellData(value);
        }
    }
    

    不创建对象的读

    /**
     * 直接用map接收数据
     *
     * @author Jiaju Zhuang
     */
    public class NoModelDataListener extends AnalysisEventListener<Map<Integer, String>> {
        private static final Logger LOGGER = LoggerFactory.getLogger(NoModelDataListener.class);
        /**
         * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收
         */
        private static final int BATCH_COUNT = 5;
        List<Map<Integer, String>> list = new ArrayList<Map<Integer, String>>();
    
        @Override
        public void invoke(Map<Integer, String> data, AnalysisContext context) {
            LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data));
            list.add(data);
            if (list.size() >= BATCH_COUNT) {
                saveData();
                list.clear();
            }
        }
    
        @Override
        public void doAfterAllAnalysed(AnalysisContext context) {
            saveData();
            LOGGER.info("所有数据解析完成!");
        }
    
        /**
         * 加上存储数据库
         */
        private void saveData() {
            LOGGER.info("{}条数据,开始存储数据库!", list.size());
            LOGGER.info("存储数据库成功!");
        }
    }
    
        /**
         * 不创建对象的读
         */
        @Test
        public void noModelRead() {
            String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
            // 这里 只要,然后读取第一个sheet 同步读取会自动finish
            EasyExcel.read(fileName, new NoModelDataListener()).sheet().doRead();
        }
    

    web中的读

        @PostMapping("upload")
        @ResponseBody
        public String upload(MultipartFile file) throws IOException {
            EasyExcel.read(file.getInputStream(), UploadData.class, new UploadDataListener(uploadDAO)).sheet().doRead();
            return "success";
        }
    
  • 相关阅读:
    百度mp3地址解密码
    VB 在EXE后附加信息
    截屏函数
    Base64和StrToByte
    The Android ION memory allocator, DMABUF is mentioned as well
    DDC EDID 介绍
    Memory management for graphic processors TTM的由来
    科普 写display driver的必看 How video card works [2D的四种主要操作]
    GEM vs TTM
    DMABUF 背景介绍文章 Sharing buffers between devices
  • 原文地址:https://www.cnblogs.com/luckyhui28/p/12693610.html
Copyright © 2020-2023  润新知