POI導入導出基本操作


POI

什么是POI

POI是Apache軟件基金會用Java編寫的免費開源的跨平台的 Java API,Apache POI提供API給Java程序對Microsoft Office格式檔案讀和寫的功能。POI為“Poor Obfuscation Implementation”的首字母縮寫,意為“簡潔版的模糊實現”。
所以POI的主要功能是可以用Java操作Microsoft Office的相關文件,但是一般我們都是用來操作Excel相關文件。

POI使用場景

  1. 將數據庫信息導出為Excle表格(俗稱:導出數據)
  2. 將Excel格式的文件導入到數據庫里(俗稱:導入數據)

操作Excel目前比較流行的就是Apache POI和阿里的easyExcel

基本功能

HSSF — 提供讀寫Microsoft Excle格式檔案的功能。 03版本

XSSF — 提供讀寫Microsoft Excle OOXML格式檔案的功能。 07版本

HWPF — 提供讀寫Microsoft Word格式檔案的功能。

HSLF — 提供讀寫Microsoft PowerPoint格式檔案的功能。

HDGF — 提供讀寫Microsoft Visio格式檔案的功能。

Excle 03 版本和 07 版本的區別

①03版的excle只能放65536條,而07版本的沒有限制

②后綴也不一樣,所以操作的工具類也不同

工作簿,工作表,行,列

POI官網:http://poi.apache.org/index.html

POI的使用

首先加入POI的依賴和測試工具依賴

<dependencies>
<!--    xls03版本-->
    <!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>3.17</version>
    </dependency>
<!--xlsx07版本-->
    <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>3.17</version>
    </dependency>
<!--    日期格式化工具-->
    <!-- https://mvnrepository.com/artifact/joda-time/joda-time -->
    <dependency>
        <groupId>joda-time</groupId>
        <artifactId>joda-time</artifactId>
        <version>2.9.9</version>
    </dependency>
<!--    junit-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </dependency>

</dependencies>

POI-簡單導出

03版本(導出操作)

String PATH = "D:\\IDEAworkspace\\POI\\lr-poi";
    @Test
    public void testWrite() throws Exception {
        //1.創建一個工作簿
        Workbook workbook = new HSSFWorkbook();
        //2.創建一個工作表
        Sheet sheet = workbook.createSheet("狂神觀眾統計表");
        //3.創建第一行
        Row row1 = sheet.createRow(0);
        //4.創建一個單元格  相當於第一行第一個(1,1)
        Cell cell1 = row1.createCell(0);
        cell1.setCellValue("今日新增觀眾");
        //相當與第一行第二個(1,2)
        Cell cell2 = row1.createCell(1);
        cell2.setCellValue(666);
        //創建第二行
        Row row2 = sheet.createRow(1);
        //創建第二行第一列  (2,1)
        Cell cell3 = row2.createCell(0);
        cell3.setCellValue("統計時間");
        //創建第二行第二列 (2,2)
        Cell cell4 = row2.createCell(1);
        String time = new DateTime().toString("yyyy-MM-dd");
        cell4.setCellValue(time);

        //生成一張表(IO流)  03版本使用xls結尾
        FileOutputStream outputStream = new FileOutputStream(PATH + "狂神統計表03.xls");
        workbook.write(outputStream);
        //關閉流
        outputStream.close();
        System.out.println("文件生成完畢!");
    }

07版本(導出操作)

  @Test
    public void testWrite1() throws Exception {
        //1.創建一個工作簿
        Workbook workbook = new XSSFWorkbook();
        //2.創建一個工作表
        Sheet sheet = workbook.createSheet("狂神觀眾統計表");
        //3.創建第一行
        Row row1 = sheet.createRow(0);
        //4.創建一個單元格  相當於第一行第一個(1,1)
        Cell cell1 = row1.createCell(0);
        cell1.setCellValue("今日新增觀眾");
        //相當與第一行第二個(1,2)
        Cell cell2 = row1.createCell(1);
        cell2.setCellValue(666);
        //創建第二行
        Row row2 = sheet.createRow(1);
        //創建第二行第一列  (2,1)
        Cell cell3 = row2.createCell(0);
        cell3.setCellValue("統計時間");
        //創建第二行第二列 (2,2)
        Cell cell4 = row2.createCell(1);
        String time = new DateTime().toString("yyyy-MM-dd");
        cell4.setCellValue(time);

        //生成一張表(IO流)  03版本使用xls結尾
        FileOutputStream outputStream = new FileOutputStream(PATH + "狂神統計表07.xlsx");
        workbook.write(outputStream);
        //關閉流
        outputStream.close();
        System.out.println("文件生成完畢!");
    }

注意:03版本和07版本只是生成的工作簿對象和后綴不同,效果相同。

POI-批量導出

小文件用HSSF 03版本

缺點:最多只能處理65536行,否則會拋出異常

java.lang.IllegalArgumentException: Invalid row number (65536) outside allowable range (0..65535)

優點:過程中寫入緩存,不操作磁盤,最后一次性寫入磁盤,速度快

 @Test
    public void testWrite2() throws Exception {
        //記錄導出65536行數據多長時間
        long begin = System.currentTimeMillis();
        //創建一個工作簿
        HSSFWorkbook workbook = new HSSFWorkbook();
        //創建表
        HSSFSheet sheet = workbook.createSheet();
        //寫入數據  此處如果rowNumber>65536就會報上邊出現的錯誤
        for(int rowNumber = 0;rowNumber<65536;rowNumber++ ){
            HSSFRow row = sheet.createRow(rowNumber);
            for (int cellNum = 0; cellNum < 10; cellNum++) {
                HSSFCell cell = row.createCell(cellNum);
                cell.setCellValue(cellNum);
            }
        }
        FileOutputStream outputStream = new FileOutputStream(PATH+"測試03.xls");
        workbook.write(outputStream);
        //關閉資源
        outputStream.close();
        long end = System.currentTimeMillis();
        System.out.println("03版本多少秒"+((double)(end-begin)/1000)); //1.947秒
    }

大文件用XSSF 07版本

缺點:寫數據時速度非常慢,非常消耗內存,也會發生內存溢出,如100萬條數據

優點:可以寫較大的數據量,如20萬條

    @Test
    public void testWrite3() throws Exception {
        //記錄導出65536行數據多長時間
        long begin = System.currentTimeMillis();
        //創建一個工作簿
        XSSFWorkbook workbook = new XSSFWorkbook();
        //創建表
        XSSFSheet sheet = workbook.createSheet();
        //寫入數據  此時可以寫入的數據可以超過65536
        for(int rowNumber = 0;rowNumber<65536;rowNumber++ ){
            XSSFRow row = sheet.createRow(rowNumber);
            for (int cellNum = 0; cellNum < 10; cellNum++) {
                XSSFCell cell = row.createCell(cellNum);
                cell.setCellValue(cellNum);
            }
        }
        FileOutputStream outputStream = new FileOutputStream(PATH+"測試07.xlsx");
        workbook.write(outputStream);
        //關閉資源
        outputStream.close();
        long end = System.currentTimeMillis();
        System.out.println("07版本多少秒"+((double)(end-begin)/1000)); //8.705秒
    }

SXSSF 是07版本的加強版 可寫入數據更多,速度更快

優點:可以寫非常大的數據量,如100萬條甚至更多條,寫數據速度快,占用更少的內存

注意:

過程中會產生臨時文件,需要清理臨時文件

默認有100條記錄被保存在內存中,如果超過這個數量,則最前面的數據被寫入臨時文件

如果想自定義內存中數據的數量,可以使用new SXSSFWorkbook(數量)

    @Test
    public void testWrite4() throws Exception {
        //記錄導出65536行數據多長時間
        long begin = System.currentTimeMillis();
        //創建一個工作簿
        SXSSFWorkbook workbook = new SXSSFWorkbook();
        //創建表
        SXSSFSheet sheet = workbook.createSheet();
        //寫入數據
        for(int rowNumber = 0;rowNumber<100000;rowNumber++ ){
            SXSSFRow row = sheet.createRow(rowNumber);
            for (int cellNum = 0; cellNum < 10; cellNum++) {
                SXSSFCell cell = row.createCell(cellNum);
                cell.setCellValue(cellNum);
            }
        }
        FileOutputStream outputStream = new FileOutputStream(PATH+"測試加速版07.xlsx");
        workbook.write(outputStream);
        //關閉資源
        outputStream.close();
        //清除臨時文件
        workbook.dispose();
        long end = System.currentTimeMillis();
        System.out.println("07加強版本多少秒"+((double)(end-begin)/1000)); //2.443秒
    }

總結:同樣是導出65536行數據,03版本用時1.947秒而07版本用時8.705秒,而導出10萬條數據07加強版本用時2.443秒。

POI導入

03版本

 @Test
    public void read1() throws Exception {
        //1.獲取文件流
        FileInputStream inputStream = new FileInputStream(PATH+"狂神統計表03.xls");
        //2.創建工作簿
        HSSFWorkbook workbook = new HSSFWorkbook(inputStream);
        //3.得到表
        HSSFSheet sheetAt = workbook.getSheetAt(0);
        //4.得到行
        HSSFRow row = sheetAt.getRow(0);
        //5.得到列
        HSSFCell cell = row.getCell(0);
        //讀取值得時候,一定要注意類型
        //cell.getNumericCellValue()獲取數字類型
        System.out.println(cell.getStringCellValue()); //獲取字符串類型
        //關閉流
        inputStream.close();
    }

07版本

@Test
public void read1() throws Exception {
    //1.獲取文件流
    FileInputStream inputStream = new FileInputStream(PATH+"狂神統計表07.xlsx");
    //2.創建工作簿
    Workbook workbook = new XSSFWorkbook(inputStream);
    //3.得到表
    Sheet sheetAt = workbook.getSheetAt(0);
    //4.得到行
    Row row = sheetAt.getRow(0);
    //5.得到列
    Cell cell = row.getCell(0);
    System.out.println(cell.getStringCellValue());
    //關閉流
    inputStream.close();
}

在做導入的時候報了一個錯誤:

org.apache.poi.openxml4j.exceptions.OLE2NotOfficeXmlFileException: The supplied data appears to be in the OLE2 Format. You are calling the part of POI that deals with OOXML (Office Open XML) Documents. You need to call a different part of POI to process this data (eg HSSF instead of XSSF)

錯誤原因:XSSF是用來解析07版本,我卻用來解析了03版本,不同版本的excle要使用對應的實現類進行解析。

導入不同的數據類型(也可以叫做通用導入)

Excle文件數據

 @Test
    public void read2() throws Exception {
        //1.獲取文件流
        FileInputStream inputStream = new FileInputStream("D:\\IDEAworkspace\\POI\\賬單.xlsx");
        //2.創建一個工作簿
        Workbook workbook = new XSSFWorkbook(inputStream);
        Sheet sheet = workbook.getSheetAt(0);
        //3.獲取標題內容
        Row rowTitle = sheet.getRow(0);
        if (rowTitle!=null){
            //rowTitle.getPhysicalNumberOfCells()是獲取這一行一共有多少列
            int cellCount = rowTitle.getPhysicalNumberOfCells();
            for (int cellNumber = 0; cellNumber < cellCount; cellNumber++) {
                Cell cell = rowTitle.getCell(cellNumber);
                if (cell!=null){
                    System.out.print(cell.getStringCellValue()+" | ");  //手機號 | 消費日期 | 小票號 | 商品編號 | 商品條碼 | 商品名稱 | 商品單位 | 原價 | 銷售價 | 銷售數量 | 銷售金額 |
                }
            }
            System.out.println();
        }

        //獲取表中的內容
        //sheet.getPhysicalNumberOfRows(); 獲取這個表中一共有多少行
        int rowCount = sheet.getPhysicalNumberOfRows();
        //因為第一行為標題,所以rowNuber要從第二行開始
        for (int rowNumber = 1; rowNumber < rowCount; rowNumber++) {
            Row rowData = sheet.getRow(rowNumber);
            if (rowData!=null){
                int cellCount = rowTitle.getPhysicalNumberOfCells();
                for (int cellNumber = 0; cellNumber < cellCount; cellNumber++) {
                    System.out.print("["+(rowNumber+1)+"-"+(cellNumber+1)+"]");
                    Cell cell = rowData.getCell(cellNumber);
                    //匹配列的數據類型
                    if (cell!=null){
                        int cellType = cell.getCellType();
                        String cellValue = "";
                        switch (cellType){
                            case XSSFCell.CELL_TYPE_STRING://字符串類型
                                System.out.print("【String】");
                                cellValue = cell.getStringCellValue();
                                break;
                            case XSSFCell.CELL_TYPE_BOOLEAN://布爾類型
                                System.out.print("【Boolen】");
                                cellValue = String.valueOf(cell.getBooleanCellValue()) ;
                                break;
                            case XSSFCell.CELL_TYPE_BLANK://空
                                System.out.print("【Blank】");//如果是空直接輸出
                                break;
                            case XSSFCell.CELL_TYPE_NUMERIC://數字(可能是日期或普通數字)
                                if (HSSFDateUtil.isCellDateFormatted(cell)){ //判斷是否是日期類型
                                    System.out.print("【Date】");
                                    Date date = cell.getDateCellValue();
                                    cellValue = new DateTime(date).toString("yyyy-MM-dd");
                                }else {  //如果不是日期類型就是數字類型
                                    //不是日期格式防止日期過長
                                    System.out.print("【轉換為字符串輸出】");
                                    cell.setCellType(XSSFCell.CELL_TYPE_STRING);
                                    cellValue = cell.toString();
                                }
                                break;
                            case XSSFCell.CELL_TYPE_ERROR://如果是異常類型直接輸出
                                System.out.print("【數據類型錯誤】");
                                break;
                        }
                        System.out.println(cellValue);
                    }
                }
            }
        }
        inputStream.close();
    }

控制台輸出:

手機號 | 消費日期 | 小票號 | 商品編號 | 商品條碼 | 商品名稱 | 商品單位 | 原價 | 銷售價 | 銷售數量 | 銷售金額 | 
[2-1]【轉換為字符串輸出】1312313
[2-2]【Date】2020-01-01
[2-3]【String】0000012312312
[2-4]【String】AA11
[2-5]【String】AA11
[2-6]【String】老壇酸菜
[2-7]【String】壇
[2-8]【轉換為字符串輸出】100
[2-9]【轉換為字符串輸出】19999
[2-10]【轉換為字符串輸出】777
[2-11]【轉換為字符串輸出】1
[3-1]【轉換為字符串輸出】123123123
[3-2]【Date】2020-01-02
[3-3]【String】000042345234
[3-4]【String】BB22
[3-5]【String】BB22
[3-6]【String】牛肉面
[3-7]【String】袋
[3-8]【轉換為字符串輸出】200
[3-9]【轉換為字符串輸出】18888
[3-10]【轉換為字符串輸出】999
[3-11]【轉換為字符串輸出】1


免責聲明!

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



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