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

原文地址:https://www.cnblogs.com/pinked/p/13594854.html