• POI和EasyExcel的使用


    POI和EasyExcel的使用

    POI是什么

    Apache POI是Apache软件基金会的开放源码函式库,POI提供API给Java程序对Microsoft Office格式档案读和写的功能.可以用于把数据导出为excel表格或者是把excel表的数据录入到数据库中.

    依赖

    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>4.1.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>4.1.2</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>
    

    excel对象

    • 工作簿(文件)

    • 工作表(sheet)

    表写入

    @Test
    public void test1() throws IOException {
        //HSSFWorkbook为03版excel表,07版使用XSSFWorkbook
        Workbook workbook = new HSSFWorkbook();
        Sheet sheet = workbook.createSheet("my_sheet");
        //第一行
        Row row_1 = sheet.createRow(0);
        //第一行的第一个单元格
        Cell cell_1_1 = row_1.createCell(0);
        cell_1_1.setCellValue("姓名");
        Cell cell_1_2 = row_1.createCell(1);
        cell_1_2.setCellValue("野原新之助");
    
        Row row_2 = sheet.createRow(1);
        Cell cell_2_1 = row_2.createCell(0);
        cell_2_1.setCellValue("年龄");
        Cell cell_2_2 = row_2.createCell(1);
        cell_2_2.setCellValue(5);
    
        //03版excel表结尾为xls,07版excel表结尾为xlsx
        FileOutputStream stream = new FileOutputStream(PATH + "test1.xls");
        workbook.write(stream);
        stream.close();
        workbook.close();
    }
    

    数据批量导入:

    • HSSF
      • 最多只能处理65536行数据
      • 过程中写入缓存,不操作磁盘,最后一次性写入磁盘,速度快
    • XSSF
      • 速度慢,耗内存,也会发生内存溢出
      • 可以写较大的数据量
    • SXSSF
      • 加速版的XSSF
      • 过程中会产生临时文件,需要清理临时文件
      • 默认100条记录保存在内存中,超过写入
      • 如果要自定义内存中的数据量:new SXSSFWorkBook(数量)
      • 清除临时文件:==((SXSSFWorkBook)workBook).dispose()

    表读取

    @Test
    public void test1() throws IOException {
        FileInputStream stream = new FileInputStream(PATH + "test1.xls");
        //使用对应的workbook打开对应版本的excel表
        Workbook workbook = new HSSFWorkbook(stream);
        Sheet sheet = workbook.getSheetAt(0);
        for (int rowNum = 0; rowNum < 2; rowNum++) {
            Row row = sheet.getRow(rowNum);
            for (int cellNum = 0; cellNum < 2; cellNum++) {
                Cell cell = row.getCell(cellNum);
                System.out.println(cell);
            }
        }
        stream.close();
        workbook.close();
    }
    

    EasyExcel是什么

    Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到几M,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便

    依赖

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>easyexcel</artifactId>
        <version>2.2.6</version>
    </dependency>
    

    简单使用

    实体类

    @Data
    public class User {
        @ExcelProperty("用户名")
        private String username;
        @ExcelIgnore
        private String password;
        @ExcelProperty("生日")
        private Date birthday;
        @ExcelProperty("余额")
        private Double money;
    }
    

    表写入

    private List<User> user(){
            List<User> list = new ArrayList<User>();
            for (int i = 0; i < 10; i++) {
                User user = new User();
                user.setUsername("用户" + i);
                user.setPassword(String.valueOf(Math.random()));
                user.setBirthday(new Date());
                user.setMoney(3.14);
                list.add(user);
            }
            return list;
    }
    
    @Test
    public void simpleWrite() {
        // 写法1
        String fileName = PATH + "user1.xlsx";
        // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        // 如果这里想使用03 则 传入excelType参数即可
        EasyExcel.write(fileName, User.class).sheet("自定义sheet名").doWrite(user());
    
        // 写法2
        fileName = PATH + "user2.xlsx";
        // 这里 需要指定写用哪个class去写
        ExcelWriter excelWriter = null;
        try {
            excelWriter = EasyExcel.write(fileName, User.class).build();
            WriteSheet writeSheet = EasyExcel.writerSheet("用户表").build();
            excelWriter.write(user(), writeSheet);
        } finally {
            // 千万别忘记finish 会帮忙关闭流
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }
    }
    

    持久层

    public class DemoDAO {
        public void save(List<User> list) {
            System.out.println("list->保存到数据库!");
        }
    }
    

    监听器

    // 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
    public class DemoDataListener extends AnalysisEventListener<User> {
        private static final int BATCH_COUNT = 5;
        List<User> list = new ArrayList<User>();
        private DemoDAO demoDAO;
    
        public DemoDataListener() {
            // 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数
            demoDAO = new DemoDAO();
        }
    
        public DemoDataListener(DemoDAO demoDAO) {
            this.demoDAO = demoDAO;
        }
    
        @Override
        public void invoke(User data, AnalysisContext context) {
            System.out.println("解析到一条数据:" + JSON.toJSONString(data));
            list.add(data);
            // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
            if (list.size() >= BATCH_COUNT) {
                saveData();
                // 存储完成清理 list
                list.clear();
            }
        }
    
        @Override
        public void doAfterAllAnalysed(AnalysisContext context) {
            // 这里也要保存数据,确保最后遗留的数据也存储到数据库
            saveData();
            System.out.println("所有数据解析完成!");
        }
    
        private void saveData() {
            System.out.println(list.size() + "条数据,开始存储数据库!");
            demoDAO.save(list);
            System.out.println("存储数据库成功!");
        }
    }
    

    表读取

    @Test
    public void simpleRead() {
        // 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
        // 写法1:
        String fileName = PATH + "user1.xlsx";
        // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
        EasyExcel.read(fileName, User.class, new DemoDataListener()).sheet().doRead();
    
        // 写法2:
        fileName = PATH + "user2.xlsx";
        ExcelReader excelReader = null;
        try {
            excelReader = EasyExcel.read(fileName, User.class, new DemoDataListener()).build();
            ReadSheet readSheet = EasyExcel.readSheet(0).build();
            excelReader.read(readSheet);
        } finally {
            if (excelReader != null) {
                // 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的
                excelReader.finish();
            }
        }
    }
    

    详细使用说明:https://www.yuque.com/easyexcel/doc

  • 相关阅读:
    phpdocumentor生成代码注释文档(linux)
    phpstorm扩展
    es教程
    康威定律
    k8s
    tidb调研
    netty 在线教程
    McQueenRPC源码阅读
    DIY一些基于netty的开源框架
    性能测试
  • 原文地址:https://www.cnblogs.com/pinked/p/13594854.html
Copyright © 2020-2023  润新知