Use code to manipulate Excel files (POI)

This article will describe how to use POI to read and write Excel files

apache's POI documentation: https://poi.apache.org

1.Maven imports the poi package

<!--导入依赖-->
    <dependencies>
        <!--xls(03版本)-->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.9</version>
        </dependency>

        <!--xlsx(07版本)-->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.9</version>
        </dependency>

        <!--日期格式化工具-->
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
            <version>2.10.1</version>
        </dependency>

        <!--junit测试-->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

Explain here why there are two versions (version 03, version 07)?
1. The file suffixes of the two are different. The 03 version is
. The number of rows in the version can be unlimited (meaning that version 07 can store more data)

Before starting the code, first understand the Excel table structure and look directly at the picture below.

Insert image description here

2. POI performs basic writing

Note: Version 03 uses HSSFWorkbook, and version 07 uses XSSFWorkbook (version 07 uses SXSSFWorkbook for large amounts of data writing). What is the
difference between version 07's XSSFWorkbook and SXSSFWorkbook? This question will be discussed below.

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.junit.Test;

import java.io.FileOutputStream;

/**
 * @author: libo
 * @date: 2020/10/8  15:22
 * @motto: 即使再小的帆也能远航
 */
public class test {
    
    

    /*文件生成路径*/
    final String PATH = "D:\\IntelliJ IDEA 2019.1_File\\POIandEasyExcel\\poi\\";

    /*03版本Excel*/
    @Test
    public void poi03() throws Exception {
    
    
        /*1.创建工作簿*/
        Workbook workbook = new HSSFWorkbook();
        /*2.创建工作表*/
        Sheet sheet = workbook.createSheet("03版本");
        /*3.创建第一行(0就是第一行,以此类推 就像数组下标一样)*/
        Row row = sheet.createRow(0);
        /*4.创建一列(单元格)(0就是第一列)*/
        Cell cell = row.createCell(0);
        cell.setCellValue("第一行第一列");
        /*4.创建一列(单元格)(1就是第二列)*/
        Cell cell2 = row.createCell(1);
        cell2.setCellValue("第一行第二列");
        /*创建第二行(1就是第二行)*/
        Row row2 = sheet.createRow(1);
        /*创建(单元格)*/
        Cell cell21 = row2.createCell(0);
        cell21.setCellValue("第二行第一列");
        Cell cell22 = row2.createCell(1);
        cell22.setCellValue("第二行第二列");

        /*5.创建输出流(IO流)  03版本文件后缀为:.xls*/
        FileOutputStream fileOutputStream = new FileOutputStream(PATH + "03Excel.xls");
        /*6.生成文件*/
        workbook.write(fileOutputStream);
        /*7.关闭流*/
        fileOutputStream.close();
    }



    /*07版本Excel*/
    @Test
    public void poi07() throws Exception {
    
    
        /*1.创建工作簿*/
        Workbook workbook = new XSSFWorkbook();
        /*2.创建工作表*/
        Sheet sheet = workbook.createSheet("07版本");
        /*3.创建第一行*/
        Row row = sheet.createRow(0);
        /*4.创建一列(单元格)*/
        Cell cell = row.createCell(0);
        cell.setCellValue("第一行第一列");
        Cell cell2 = row.createCell(1);
        cell2.setCellValue("第一行第二列");
        /*创建第二行*/
        Row row2 = sheet.createRow(1);
        /*创建(单元格)*/
        Cell cell21 = row2.createCell(0);
        cell21.setCellValue("第二行第一列");
        Cell cell22 = row2.createCell(1);
        cell22.setCellValue("第二行第二列");

        /*5.创建输出流(IO流)  07版本文件后缀为:.xlsx*/
        FileOutputStream fileOutputStream = new FileOutputStream(PATH + "07Excel.xlsx");
        /*6.生成文件*/
        workbook.write(fileOutputStream);
        /*7.关闭流*/
        fileOutputStream.close();
    }
}

3.POI writes large amounts of data

Simulate the writing of a large amount of data, write 65536 rows, 10 columns (10 cells per row) of data
and record the time spent by the program

    /*大量数据写入03版本Excel*/
    @Test
    public void poi03BigDate() throws Exception {
    
    

        /*记录程序开始时间*/
        long begin = System.currentTimeMillis();

        /*1.创建工作簿*/
        Workbook workbook = new HSSFWorkbook();
        /*2.创建工作表*/
        Sheet sheet = workbook.createSheet("03版本大量数据写入");

        /*x:行 y:列(单元格)*/
        for (int x = 0; x < 65536; x++) {
    
    
            /*3.创建行*/
            Row row = sheet.createRow(x);
            for (int y = 0; y < 10; y++) {
    
    
                /*4.创建列(单元格)*/
                Cell cell = row.createCell(y);
                cell.setCellValue(y);
            }
        }

        /*5.创建输出流(IO流)  03版本文件后缀为:.xls*/
        FileOutputStream fileOutputStream = new FileOutputStream(PATH + "03BIgDate.xls");
        /*6.生成文件*/
        workbook.write(fileOutputStream);
        /*7.关闭流*/
        fileOutputStream.close();

        /*记录程序结束时间*/
        long end = System.currentTimeMillis();

        /*耗时 = 结束时间 - 开始时间 / 1000(毫秒值)*/
        System.out.println("HSSF_03版耗时:" + (double) (end - begin) / 1000);
    }


    /*大量数据写入07版本Excel*/
    @Test
    public void poi07BigDate() throws Exception {
    
    

        /*记录程序开始时间*/
        long begin = System.currentTimeMillis();

        /*1.创建工作簿*/
        Workbook workbook = new XSSFWorkbook();
        //Workbook workbook = new SXSSFWorkbook();
        
        /*2.创建工作表*/
        Sheet sheet = workbook.createSheet("07版本大量数据写入");

        /*x:行 y:列(单元格)*/
        for (int x = 0; x < 65536; x++) {
    
    
            /*3.创建行*/
            Row row = sheet.createRow(x);
            for (int y = 0; y < 10; y++) {
    
    
                /*4.创建列(单元格)*/
                Cell cell = row.createCell(y);
                cell.setCellValue(y);
            }
        }

        /*5.创建输出流(IO流)  07版本文件后缀为:.xlsx*/
        FileOutputStream fileOutputStream = new FileOutputStream(PATH + "07BIgDate.xlsx");
        /*6.生成文件*/
        workbook.write(fileOutputStream);
        /*7.关闭流*/
        fileOutputStream.close();

        /*记录程序结束时间*/
        long end = System.currentTimeMillis();

        /*耗时 = 结束时间 - 开始时间 / 1000(毫秒值)*/
        System.out.println("XSSF_07版耗时:" + (double) (end - begin) / 1000);
    }

If version 03 writes more than 65536 lines of data, an exception will occur (this is the big difference between version 03 and version 07, and the suffix names are different, version 03 is .xls, version 07 is .xlsx):

Insert image description here

The 03 version of HSSF is time-consuming:
Advantages: writing to the cache during the process, no disk operation, and finally writing to the disk at once, fast
Disadvantages: can only operate 65536 rows of data, otherwise an exception will be thrown
(java.lang.IllegalArgumentException: Invalid row number (65536) outside allowable range (0…65535))

Insert image description here

The 07 version of XSSF is time-consuming:
Advantages: It can write very large amounts of data, such as hundreds of thousands.
Disadvantages: Writing data is very slow and consumes a lot of memory, so memory overflow (OOM) is very likely to occur.

Insert image description here

The 07 version of SXSSF is time-consuming (the 07 version replaces the XSSFWorkbook object with the SXSSFWorkbook object):
Advantages: When writing a huge amount of data, it takes less time and occupies less memory.
Note: When writing data, some parts will be first Write to a temporary file. After execution, the temporary file needs to be cleaned up. If you want to customize the number in memory, you can new SXSSFWorkbook (pass in the number)

Insert image description here
Excel writing summary:

4. POI reads data (simulating two cases)

Note:
1. This case is only for Excel version 03 (if it is Excel version 07, just replace the workbook object and change HSSFWorkbook to XSSFWorkbook)
2. The most complicated point in reading data is to convert the data in the Excel table. For example, dates, numbers, decimals, strings, function formulas in Excel, and empty cells
3. Therefore, you can use switch case to judge and match different types.

Case number one:

There is an Excel table below. Take out the data and output it to the console (it is already in the console, can't it be stored in the database?):

Insert image description here

    /*读取03版本Excel中多个类型数据*/
    @Test
    public void poi03read() throws Exception {
    
    

        /*获得文件流*/
        FileInputStream FileInputStream = new FileInputStream(PATH + "会员消费商品明细表.xls");

        /*1.创建工作簿*/
        Workbook workbook = new HSSFWorkbook(FileInputStream);

        /*2.得到工作表(一个文件中可能有多个工作表,参数为 索引)*/
        Sheet sheetAt = workbook.getSheetAt(0);

        /*3.获得工作表中所有行*/
        int rowCount = sheetAt.getPhysicalNumberOfRows();

        /*循环所有行*/
        for (int rowNum = 0; rowNum < rowCount; rowNum++) {
    
    
            /*读取行*/
            Row row = sheetAt.getRow(rowNum);
            
            if (row != null) {
    
    
            
                /*4.获得所有列*/
                int cellCount = row.getPhysicalNumberOfCells();
                
                /*循环所有列*/
                for (int cellNum = 0; cellNum < cellCount; cellNum++) {
    
    
                
                    /*获得列(单元格)*/
                    Cell cell = row.getCell(cellNum);
                    
                    /*判断列不为null*/
                    if (cell != null) {
    
    
                        /*获得单元格内容的类型*/
                        int cellType = cell.getCellType();
                        
                        /*内容变量*/
                        String cellValue = "";
                        
                        /*先判断类型,再输出*/
                        switch (cellType) {
    
    
                            /*String类型*/
                            case Cell.CELL_TYPE_STRING:
                                cellValue = cell.getStringCellValue();
                                System.out.print(cellValue + " ");
                                break;
                                
                            /*boolean类型*/
                            case Cell.CELL_TYPE_BOOLEAN:
                                cellValue = String.valueOf(cell.getBooleanCellValue());
                                System.out.print(cellValue + " ");
                                break;
                                
                            /*数字类型(包括日期,数字)*/
                            case Cell.CELL_TYPE_NUMERIC:
                                /*HSSF工具类判断是否为日期*/
                                if (HSSFDateUtil.isCellDateFormatted(cell)) {
    
    
                                    Date date = cell.getDateCellValue();
                                    /*将日期时间转为字符串*/
                                    cellValue = new DateTime(date).toString("yyyy-MM-dd");
                                    System.out.print(cellValue);
                                } else {
    
    
                                    /*不是日期类型 代表是数字,再将它转为字符串*/
                                    cell.setCellType(Cell.CELL_TYPE_STRING);
                                    cellValue = cell.getStringCellValue();
                                    System.out.print(cellValue + " ");
                                }
                                break;
                                
                            /*类型错误*/
                            case Cell.CELL_TYPE_ERROR:
                                break;
                                
                            /*空*/
                            case Cell.CELL_TYPE_BLANK:
                                break;
                        }
                    }
                }
            }
            /*换行*/
            System.out.println();
        }
        /*5.关闭流*/
        FileInputStream.close();
    }

Case 2:

There is an Excel table below, read it out and output it to the console (get the sum value and the function formula in the cell):

Insert image description here

    /*读取03版本Excel中的函数公式(包括结果)*/
    @Test
    public void poi03readFormula() throws Exception {
    
    

        /*获得文件流*/
        FileInputStream FileInputStream = new FileInputStream(PATH + "计算公式.xls");

        /*1.创建工作簿*/
        Workbook workbook = new HSSFWorkbook(FileInputStream);

        /*2.得到工作表(一个文件中可能有多个工作表,参数为 索引)*/
        Sheet sheetAt = workbook.getSheetAt(0);

        /*3.获得工作表中所有行*/
        int rowCount = sheetAt.getPhysicalNumberOfRows();

        /*循环所有行*/
        for (int rowNum = 0; rowNum < rowCount; rowNum++) {
    
    
            /*读取行*/
            Row row = sheetAt.getRow(rowNum);
            if (row != null) {
    
    
                /*4.获得所有列*/
                int cellCount = row.getPhysicalNumberOfCells();
                /*循环所有列*/
                for (int cellNum = 0; cellNum < cellCount; cellNum++) {
    
    
                    /*获得列(单元格)*/
                    Cell cell = row.getCell(cellNum);
                    /*判断列不为null*/
                    if (cell != null) {
    
    
                        /*获得单元格内容的类型*/
                        int cellType = cell.getCellType();
                        /*内容变量*/
                        String cellValue = "";
                        /*先判断类型,再输出*/
                        switch (cellType) {
    
    
                            /*函数公式*/
                            case Cell.CELL_TYPE_FORMULA:

                                cell.setCellType(Cell.CELL_TYPE_FORMULA);

                                /*获得函数公式*/
                                String formula = cell.getCellFormula();

                                System.out.println(formula);

                                /*获得函数公式结果*/
                                /*创建*HSSFFormulaEvaluator对象*/
                                FormulaEvaluator formulaEvaluator = new HSSFFormulaEvaluator((HSSFWorkbook) workbook);

                                CellValue evaluate = formulaEvaluator.evaluate(cell);

                                cellValue = evaluate.formatAsString();

                                System.out.println(cellValue);
                                break;
                        }
                    }
                }
            }
        }
        /*5.关闭流*/
        FileInputStream.close();
    }
Because the memories are too painful, we have to keep moving forward.

Guess you like

Origin blog.csdn.net/weixin_45377770/article/details/108965817