1. 程式人生 > 實用技巧 >POI 讀寫excel表格

POI 讀寫excel表格

目錄

POI 讀寫excel表格

POI是Apache軟體基金會的,POI為“Poor Obfuscation Implementation”的首字母縮寫,意為“簡潔版的模糊實現”。
所以POI的主要功能是可以用Java操作Microsoft Office的相關檔案

,這裡我們主要講Excel

1. 寫入

1.1 pom依賴

<!--2003(xls)-->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.17</version>
</dependency>
<!--2007(xlsx)版本-->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.17</version>
</dependency>

所謂03版和07版最大的區別在於 03版表格最多支援65536行, 而07版則沒有上限

1.2 基本功能

結構
  • HSSF - 提供讀寫Microsoft Excel格式文件的功能 (03版)
  • XSSF - 提供讀寫Microsoft Excel OOXML格式文件的功能(07版)
  • HWPF - 提供讀寫Microsoft Word格式文件的功能(word文件)
  • HSLF - 提供讀寫Microsoft PowerPoint格式文件的功能(PPT幻燈片)
  • HDGF - 提供讀寫Microsoft Visio格式文件的功能

1.3 Workbook介面的三個實現類

實現類 描述
HSSFWorkbook() 03版寫入
XSSFWorkbook() 07版寫入 (把所有的資料儲存到記憶體 ,再寫入到檔案.
可能發生記憶體洩露)
SXSSFWorkbook() 寫入速度快, 佔用更少的記憶體. 中間會產生一個臨時檔案,
需要清理臨時檔案, 預設由100條記錄被儲存到記憶體中,
如果超出這個範圍,則被寫入到臨時檔案中,如果想自
定義記憶體中的數量 ,可以 new SXSSFWorkbook(數量) 來進行定義

1.4 寫入檔案演示 (03版)

// 生成檔案路徑定義
String PATH = "/home/zpk/DEV/idea/workspace/poi/";

@Test
public void testWrite03() throws Exception {
    // 1. 建立一個工作簿
    Workbook workbook = new HSSFWorkbook();
    // 2. 建立一個工作表
    Sheet sheet = workbook.createSheet("統計表");

    // 3. 建立一個行 (第一行)
    Row row1 = sheet.createRow(0);
    // 建立單元格(1,1)
    Cell cell11 = row1.createCell(0);
    // 單元格(1,1)寫入內容
    cell11.setCellValue("今日新增觀眾");
    // 建立單元格(1,2)
    Cell cell12 = row1.createCell(1);
    // 單元格(1,2)寫入內容
    cell12.setCellValue(666);

    // 第二行
    Row row2 = sheet.createRow(1);
    Cell cell21 = row2.createCell(0);
    cell21.setCellValue("統計時間");
    Cell cell22 = row2.createCell(1);
    String time = new DateTime().toString("yyyy-MM-dd HH:mm:ss");
    cell22.setCellValue(time);

    // 生成一張表(IO流) 03 版本就是使用xls結尾
    FileOutputStream fileOutputStream = new FileOutputStream(PATH + "統計表03版.xls");
    // 寫出檔案
    workbook.write(fileOutputStream);
    // 關閉流
    fileOutputStream.close();

    System.out.println("檔案生成完畢");

}

1.5 寫入檔案演示 (07版)

// 生成檔案路徑定義
String PATH = "/home/zpk/DEV/idea/workspace/poi/";

@Test
public void testWrite07() throws Exception {
    // 1. 建立一個工作簿
    Workbook workbook = new XSSFWorkbook();
    // 2. 建立一個工作表
    Sheet sheet = workbook.createSheet("統計表");

    // 3. 建立一個行 (第一行)
    Row row1 = sheet.createRow(0);
    // 建立單元格(1,1)
    Cell cell11 = row1.createCell(0);
    // 單元格(1,1)寫入內容
    cell11.setCellValue("今日新增觀眾");
    // 建立單元格(1,2)
    Cell cell12 = row1.createCell(1);
    // 單元格(1,2)寫入內容
    cell12.setCellValue(666);

    // 第二行
    Row row2 = sheet.createRow(1);
    Cell cell21 = row2.createCell(0);
    cell21.setCellValue("統計時間");
    Cell cell22 = row2.createCell(1);
    String time = new DateTime().toString("yyyy-MM-dd HH:mm:ss");
    cell22.setCellValue(time);

    // 生成一張表(IO流) 03 版本就是使用xls結尾
    FileOutputStream fileOutputStream = new FileOutputStream(PATH + "統計表07版.xlsx");
    // 寫出檔案
    workbook.write(fileOutputStream);
    // 關閉流
    fileOutputStream.close();

    System.out.println("檔案生成完畢");

}

可見 若生成07版只需要把Workbook workbook = new HSSFWorkbook();改為 Workbook workbook = new XSSFWorkbook(); 並且生成的檔案字尾改為xlsx就可以了 ,這就是面向藉口程式設計的好處

1.6 (HSSF) 03版寫入大量資料

預設寫入65536行資料, 檢視所需要的時間

// 生成檔案路徑定義
String PATH = "/home/zpk/DEV/idea/workspace/poi/";

@Test
public void testWrite03BigData() throws Exception {

    long begin = System.currentTimeMillis(); // 開始時間

    // 建立一個簿
    Workbook workbook = new HSSFWorkbook();
    // 建立表
    Sheet sheet = workbook.createSheet();
    // 寫入資料
    for (int rowNum = 0; rowNum < 65536; rowNum++) {
        // 一共65536行
        Row row = sheet.createRow(rowNum);
        for (int cellNum = 0; cellNum < 10; cellNum++) {
            // 每列十條資料
            Cell cell = row.createCell(cellNum);
            cell.setCellValue(cellNum);
        }
    }
    System.out.println("over");
    // 輸出流
    FileOutputStream fileOutputStream = new FileOutputStream(PATH + "bigData03");
    // 輸出
    workbook.write(fileOutputStream);
    // 關閉流
    fileOutputStream.close();

    long end = System.currentTimeMillis(); // 結束時間
    // 時間結算
    System.out.println((double)(end - begin)/1000 + " s");
}

執行結果: 總共耗時2.036秒

over
2.036 s

注意: 03版如果行數大於65536則丟擲異常

1.7 (XSSF) 07版寫入大量資料

// 生成檔案路徑定義
String PATH = "/home/zpk/DEV/idea/workspace/poi/";

@Test
public void testWrite07BigData() throws Exception {
    // 時間
    long begin = System.currentTimeMillis();

    // 建立一個簿
    Workbook workbook = new XSSFWorkbook();
    // 建立表
    Sheet sheet = workbook.createSheet();
    // 寫入資料
    for (int rowNum = 0; rowNum < 65536; rowNum++) {
        Row row = sheet.createRow(rowNum);
        for (int cellNum = 0; cellNum < 10; cellNum++) {
            Cell cell = row.createCell(cellNum);
            cell.setCellValue(cellNum);
        }
    }
    System.out.println("over");
    FileOutputStream fileOutputStream = new FileOutputStream(PATH + "bigData07.xlsx");
    workbook.write(fileOutputStream);
    fileOutputStream.close();

    long end = System.currentTimeMillis();
    System.out.println((double)(end - begin)/1000 + " s");
}

執行結果: 總共耗時8.015 秒

over
8.015 s

1.8 (SXSSF) 寫入大量資料

// 生成檔案路徑定義
String PATH = "/home/zpk/DEV/idea/workspace/poi/";

@Test
public void testWriteSXSSFBigData() throws Exception {
    // 時間
    long begin = System.currentTimeMillis();

    // 建立一個簿
    Workbook workbook = new SXSSFWorkbook();
    // 建立表
    Sheet sheet = workbook.createSheet();
    // 寫入資料
    for (int rowNum = 0; rowNum < 65536; rowNum++) {
        Row row = sheet.createRow(rowNum);
        for (int cellNum = 0; cellNum < 10; cellNum++) {
            Cell cell = row.createCell(cellNum);
            cell.setCellValue(cellNum);
        }
    }
    System.out.println("over");
    FileOutputStream fileOutputStream = new FileOutputStream(PATH + "bigDataSXSSF.xlsx");
    workbook.write(fileOutputStream);
    fileOutputStream.close();

    // 清除臨時檔案
    ((SXSSFWorkbook) workbook).dispose();

    long end = System.currentTimeMillis();
    System.out.println((double)(end - begin)/1000 + " s");
}

結果: 2.192 秒

over
2.192 s

注意: 使用SXSSFWorkbook時需要清理臨時檔案

// 清除臨時檔案
((SXSSFWorkbook) workbook).dispose();

1.9 寫入大量資料結論

  • HSSF 寫入大量資料v

    • 優點: 可以寫入快速寫入資料
    • 缺點: 只能寫入65536行資料, 非常有限
  • XSSF 寫入大量資料

    • 優點: 可以寫入任意條資料

    • 缺點: 寫入速度慢的一批

  • SXSSF 寫入大量資料

    • 優點: 快速而且佔用記憶體少
    • 缺點: 仍然可能會消耗大量記憶體, 這些記憶體基於正在使用的功能,例如合併區域, 註釋仍然會儲存在記憶體中, 因此如果廣泛使用, 可能需要大量的記憶體

2. 讀取

2.1讀取檔案演示(03版)

// 路徑
String PATH = "/home/zpk/DEV/idea/workspace/poi/";

@Test
public void testRead03() throws Exception {
    // 獲取檔案流
    FileInputStream inputStream = new FileInputStream(PATH + "統計表03版.xls");
    // 1. 建立一個工作簿
    Workbook workbook = new HSSFWorkbook(inputStream);
    // 2. 獲取一個工作表, getSheetAt()方法是根據下標獲取
    Sheet sheet = workbook.getSheetAt(0);
    // 3. 得到行
    Row row = sheet.getRow(0);
    // 4. 得到單元格
    Cell cell = row.getCell(0);

    // 顯示(1,1)的內容, 獲取字串
    System.out.println(cell.getStringCellValue());

    // 關閉流
    inputStream.close();
}

結果: (獲取到了上面寫入中的1.4中生成的檔案)

今日新增觀眾

2.2 讀取檔案演示(07版)

// 路徑
String PATH = "/home/zpk/DEV/idea/workspace/poi/";

@Test
public void testRead07() throws Exception {
    // 獲取檔案流
    FileInputStream inputStream = new FileInputStream(PATH + "統計表07版.xlsx");
    // 1. 建立一個工作簿
    Workbook workbook = new XSSFWorkbook(inputStream);
    // 2. 獲取一個工作表, getSheetAt()方法是根據下標獲取
    Sheet sheet = workbook.getSheetAt(0);
    // 3. 得到行
    Row row = sheet.getRow(0);
    // 4. 得到單元格
    Cell cell = row.getCell(1);

    // 顯示(1,1)的內容, 獲取數字型別
    System.out.println(cell.getNumericCellValue());

    // 關閉流
    inputStream.close();
}

結果: (獲取到了上面寫入中的1.5中生成的文檔案)

666.0

2.3 獲取一行的資料(重點)

Row rows = sheet.getRow(0); // 獲取第一行
if (rows != null) {
    int cellCount = rows.getPhysicalNumberOfCells(); // 計數,次行多少列存入cellCount中
    for (int cellNum = 0; cellNum < cellCount; cellNum++){ // 遍歷列
        Cell cell = rows.getCell(cellNum); // 獲取每一列
        if (cell != null) {
            int cellType = cell.getCellType(); // 每一列的資料型別(列舉)
            String cellValue = cell.getStringCellValue(); // 獲取字串內容
            System.out.print(cellValue + " | "); // 分割線
        }
    }
    System.out.println() // 換行
}

2.4 獲取整張表的內容

(工具類), 只需要傳入輸入流即可

// 提取為工具類
public void read07Excel(FileInputStream inputStream) throws Exception {
    // 1. 建立一個工作簿
    Workbook workbook = new XSSFWorkbook(inputStream);
    // 2. 獲取一個工作表, getSheetAt()方法是根據下標獲取
    Sheet sheet = workbook.getSheetAt(0);


    Row rows = sheet.getRow(0); // 獲取第一行
    if (rows != null) {
        int cellCount = rows.getPhysicalNumberOfCells(); // 計數,次行多少列存入cellCount中
        for (int cellNum = 0; cellNum < cellCount; cellNum++){ // 遍歷列
            Cell cell = rows.getCell(cellNum); // 獲取每一列
            if (cell != null) {
                int cellType = cell.getCellType(); // 每一列的資料型別(列舉)
                String cellValue = cell.getStringCellValue(); // 獲取字串內容
                System.out.print(cellValue + " | "); // 分割線
            }
        }
        System.out.println(); // 換行
    }

    int rowCount = sheet.getPhysicalNumberOfRows();
    for (int rowNum = 1; rowNum < rowCount; rowNum++) {
        Row rowData = sheet.getRow(rowNum);
        if (rowData != null) {
            // 讀取列
            int cellCount = rows.getPhysicalNumberOfCells();
            for (int cellNum = 0; cellNum < cellCount; cellNum++) {
                System.out.println("[" + (rowNum + 1) + "-" + (cellNum + 1) + "]");

                Cell cell = rowData.getCell(cellNum);
                // 匹配列的資料型別
                if (cell != null) {
                    int cellType = cell.getCellType();
                    String cellValue = "";

                    switch (cellType) {
                        case HSSFCell.CELL_TYPE_STRING : // 字串
                            System.out.print("[String]");
                            cellValue = cell.getStringCellValue();
                            break;
                        case HSSFCell.CELL_TYPE_BOOLEAN : // 布林型
                            System.out.print("[Boolean]");
                            cellValue = String.valueOf(cell.getStringCellValue());
                            break;
                        case HSSFCell.CELL_TYPE_BLANK : // 空
                            System.out.print("[Blank]");
                            break;
                        case HSSFCell.CELL_TYPE_NUMERIC : // 數字(日期和普通數字
                            System.out.print("[Number]");
                            if (HSSFDateUtil.isCellDateFormatted(cell)) { // 日期
                                System.out.print("[日期]");
                                Date date = cell.getDateCellValue();
                                cellValue = new DateTime(date).toString("yyyy-MM-dd");
                            } else { // 數字, 直接轉換為字串輸出
                                // 不是日期格式, 防止數字過長!
                                System.out.print("[轉為字串輸出]");
                                cell.setCellType(HSSFCell.CELL_TYPE_STRING);
                                cellValue = String.valueOf(cell.getStringCellValue());
                                cellValue = cell.toString();
                            }
                            break;
                        case HSSFCell.CELL_TYPE_ERROR : // 布林型
                            System.out.print("[資料型別錯誤]");
                            break;
                    }
                    System.out.println(cellValue);
                }
            }
        }
    }

    // 關閉流
    inputStream.close();
}