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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM