Java 实现 Apach POI

Apach POI

  • 一、简介
  • 二、应用场景
  • 三、实现POI
    • 3.0 学前
    • 3.1 创建maven工程,项目结构
    • 3.2 pom.xml
    • 3.3 POI 基本写(03版本)
    • 3.4 POI 基本写(07版本)
    • 3.5 对于大文件的操作(03版本)
    • 3.6 对于大文件的操作(07版本)
    • 3.7 对于大文件操作(Plus版本)
    • 3.8 POI 读(难点)
    • 3.9 测试结果
  • 四、EasyExcel
  • 五、教程推荐

一、简介

Apache POI(Poor Obfuscation Implementation)是一个开源的Java类库,用于读取和写入Microsoft Office格式的文档,包括Excel、Word和PowerPoint等。它为Java开发者提供了操作这些文档格式的API,使得开发者可以在自己的应用程序中进行文档的创建、修改和提取数据。

Apache POI提供了几个组件来处理不同的文档类型:

HSSF(Horrible Spreadsheet Format):主要用于操作Excel文件(.xls),支持98-2003版本的Excel文件。

XSSF(XML Spreadsheet Format):主要用于操作Excel文件(.xlsx),支持2007及以上版本的Excel文件。

SXSSF(Streaming XML Spreadsheet Format):用于处理大型Excel文件,通过基于XML的流形式处理,避免了将整个文件加载到内存中的限制。

HWPF(Horrible Word Processor Format):用于操作Word文件(.doc)。

XWPF(XML Word Processor Format):用于操作Word文件(.docx),支持2007及以上版本的Word文件。

HSLF(Horrible Slide Layout Format):用于操作PowerPoint文件(.ppt)。

XSLF(XML Slide Layout Format):用于操作PowerPoint文件(.pptx),支持2007及以上版本的PowerPoint文件。

Apache POI提供了丰富的API来读取、写入、编辑和操作这些文档,包括样式设置、数据提取、单元格合并、图表生成等功能。它是一个十分流行和广泛使用的Java类库,被广泛用于开发各种处理Office文档的应用程序、自动化处理任务、数据分析和报告生成等场景。

你可以在Apache POI的官方网站(https://poi.apache.org/)上找到详细的文档、示例和相关资源,以帮助你了解和使用该类库


二、应用场景

数据的导入与导出

利用Apache POI,可以轻松地将数据从Excel文件中导入到数据库或其他系统中,或将数据从数据库或其他系统导出为Excel文件。这在数据迁移、数据交换和数据备份等方面非常有用。

自动化处理任务

Apache POI可以用于构建自动化处理任务,例如定时从Excel文件中读取数据并触发其他业务逻辑。通过编写Java代码,你可以实现灵活的自动化处理流程,提高工作效率和减少人工错误。

数据清洗和转换

Excel文件中的数据往往需要进行清洗和转换,以满足特定的数据标准和要求。Apache POI可以帮助你读取Excel文件中的数据,然后进行数据清洗、格式转换、数据合并等操作,以生成符合预期格式的数据。

导出数据到Excel文件

除了从Excel文件中导入数据外,Apache POI也可以将数据从数据库或其他系统导出为Excel文件。这在需要将数据以Excel格式进行共享、分发或展示时非常有用,例如向用户提供具有格式化的报表、数据展示、数据可视化等功能。


三、实现POI

3.0 学前

xls 和 xlsx文件的区别

注意:下面是文件的最大容量,实际还需要考虑别的因素,对文件容量的影响,例如工作表的数量、单元格内容的复杂度、格式和公式的使用,且文件容量可能会受到计算机硬件和软件的限制~

xls(03版本)最大的容量是:

  • 行:65536
  • 列:256

xlsx(07版本)最大的容量是:

  • 行:1,048,576
  • 列:16,384

xls和xlsx是不同的Excel文件格式,其中xlsx是一种较新的格式,基于XML,对于大型数据文件和一些高级功能提供了更好的支持。根据Microsoft的推荐,使用xlsx格式是更好的选择,除非你需要与较早版本的Excel进行兼容。

3.1 创建maven工程,项目结构

Java 实现 Apach POI_第1张图片

3.2 pom.xml

<dependencies>
    
    <dependency>
      <groupId>org.apache.poigroupId>
      <artifactId>poiartifactId>
      <version>4.1.2version>
    dependency>

    
    <dependency>
      <groupId>org.apache.poigroupId>
      <artifactId>poi-ooxmlartifactId>
      <version>4.1.2version>
    dependency>

    
    <dependency>
      <groupId>joda-timegroupId>
      <artifactId>joda-timeartifactId>
      <version>2.10.1version>
    dependency>

    
    <dependency>
      <groupId>junitgroupId>
      <artifactId>junitartifactId>
      <version>4.13.2version>
    dependency>
  dependencies>

3.3 POI 基本写(03版本)

public class ExcelService {
	/* excel文件存放路径 */
    String PATH = "G:\\Java\\Excel\\POI\\";

    /**
     * 文件基本写(03版本)
     * 注意:创建的象 new HSSFWorkbook();
     * 		文件后缀:.xls
     */
    @Test
    public void write03() throws IOException {
        // 1、创建工作簿
        Workbook workbook = new HSSFWorkbook();
        // 2、创建表 (通过工作簿创建表)
        Sheet sheet = workbook.createSheet();
        // 3、创建行 (row)  0表示第一行
        Row row1 = sheet.createRow(0);
        // 4、创建单元格 (根据行,来填充单元格) 0表示第一列
        /* 第一行,第一列 */
        Cell cell11 = row1.createCell(0);
        cell11.setCellValue("账号");
        /* 第一行,第二列 */
        Cell cell12 = row1.createCell(1);
        cell12.setCellValue("密码");
        /* 第一行,第三列 */
        Cell cell13 = row1.createCell(2);
        cell13.setCellValue("email");
        /* 第一行,第四列 */
        Cell cell14 = row1.createCell(3);
        cell14.setCellValue("状态");
        /* 第一行,第五列 */
        Cell cell15 = row1.createCell(4);
        cell15.setCellValue("创建时间");
        /* 第一行,第六列 */
        Cell cell16 = row1.createCell(5);
        cell16.setCellValue("是否为空");

        Row row21 = sheet.createRow(1);
        /* 第二行,第一列 */
        Cell cell21 = row21.createCell(0);
        cell21.setCellValue("123456789");
        /* 第二行,第二列 */
        Cell cell22 = row21.createCell(1);
        cell22.setCellValue("987654321");
        /* 第二行,第三列 */
        Cell cell23 = row21.createCell(2);
        cell23.setCellValue("123456789@@qq.com");
        /* 第二行,第四列 */
        Cell cell24 = row21.createCell(3);
        cell24.setCellValue("true");
        /* 第二行,第五列 */
        Cell cell25 = row21.createCell(4);
        cell25.setCellValue(new DateTime().toString("yyyy-MM-dd HH:mm:ss"));
        /* 第二行,第六列 */
        Cell cell26 = row21.createCell(5);

        // 5、保存到本地
        FileOutputStream savePath = new FileOutputStream(PATH + "文件基本写(03版本).xls");

        // 6、将数据写到指定路径
        workbook.write(savePath);

        // 7、刷流、关流
        savePath.flush();

        savePath.close();

        System.out.println("文件基本写(03版本)生产完毕~!");

    }
}

3.4 POI 基本写(07版本)

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.joda.time.DateTime;
import org.junit.Test;

import java.io.FileOutputStream;
import java.io.IOException;

public class ExcelService {

    /* excel文件存放路径 */
    String PATH = "G:\\Java\\Excel\\POI\\";

    /**
     * 文件基本写(07版本)
     * 注意:创建的象 new XSSFWorkbook();
     *      文件的后缀:.xlsx
     */
    @Test
    public void write07() throws IOException {
        // 1、创建工作簿
        Workbook workbook = new XSSFWorkbook();
        // 2、创建表 (通过工作簿创建表)
        Sheet sheet = workbook.createSheet();
        // 3、创建行 (row)  0表示第一行
        Row row1 = sheet.createRow(0);
        // 4、创建单元格 (根据行,来填充单元格) 0表示第一列
        /* 第一行,第一列 */
        Cell cell11 = row1.createCell(0);
        cell11.setCellValue("账号");
        /* 第一行,第二列 */
        Cell cell12 = row1.createCell(1);
        cell12.setCellValue("密码");
        /* 第一行,第三列 */
        Cell cell13 = row1.createCell(2);
        cell13.setCellValue("email");
        /* 第一行,第四列 */
        Cell cell14 = row1.createCell(3);
        cell14.setCellValue("状态");
        /* 第一行,第五列 */
        Cell cell15 = row1.createCell(4);
        cell15.setCellValue("创建时间");
        /* 第一行,第六列 */
        Cell cell16 = row1.createCell(5);
        cell16.setCellValue("是否为空");

        Row row21 = sheet.createRow(1);
        /* 第二行,第一列 */
        Cell cell21 = row21.createCell(0);
        cell21.setCellValue("123456789");
        /* 第二行,第二列 */
        Cell cell22 = row21.createCell(1);
        cell22.setCellValue("987654321");
        /* 第二行,第三列 */
        Cell cell23 = row21.createCell(2);
        cell23.setCellValue("123456789@@qq.com");
        /* 第二行,第四列 */
        Cell cell24 = row21.createCell(3);
        cell24.setCellValue("true");
        /* 第二行,第五列 */
        Cell cell25 = row21.createCell(4);
        cell25.setCellValue(new DateTime().toString("yyyy-MM-dd HH:mm:ss"));
        /* 第二行,第六列 */
        Cell cell26 = row21.createCell(5);

        // 5、保存到本地
        FileOutputStream savePath = new FileOutputStream(PATH + "文件基本写(07版本).xlsx");

        // 6、将数据写到指定路径
        workbook.write(savePath);

        // 7、刷流、关流
        savePath.flush();

        savePath.close();

        System.out.println("文件基本写(07版本)生产完毕~!");

    }
}

在这里插入图片描述
内容都是一样的,只是文件的结构不一样~
在这里插入图片描述

3.5 对于大文件的操作(03版本)

  • 好处:写入的过程,使用了缓存,不做磁盘操作,一次性写入磁盘,熟读快
  • 缺点:最多只能操作65536行数据,多了会报错
  • 65536行代码的运行时间:1.053s(根据自身电脑配置,做判断)
package com.hui.service;

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.junit.Test;

import java.io.FileOutputStream;
import java.io.IOException;

public class ExcelService {

    /* excel文件存放路径 */
    String PATH = "G:\\Java\\Excel\\POI\\";

    /**
     * 大文件写(03版本)
     * 注意:创建的象 new HSSFWorkbook();
     * 文件后缀:.xls
     * 最大范围:65536,超出会报错
     */
    @Test
    public void write03Big() throws IOException {
        // 程序开始时间
        long begin = System.currentTimeMillis();

        // 1、创建工作簿
        Workbook workbook = new HSSFWorkbook();
        // 2、创建表
        Sheet sheet = workbook.createSheet();
        // 3、创建65536行数据,看看总运行时间
        for (int rowNum = 0; rowNum < 65536; rowNum++) {
            Row row = sheet.createRow(rowNum);
            // 每列生产 0 - 9
            for (int cellNum = 0; cellNum < 10; cellNum++) {
                Cell cell = row.createCell(cellNum);
                cell.setCellValue(cellNum);
            }
        }

        // 5、保存到本地
        FileOutputStream savePath = new FileOutputStream(PATH + "大文件写(03版本).xls");

        // 6、将数据写到指定路径
        workbook.write(savePath);

        // 7、刷流、关流
        savePath.flush();

        savePath.close();

        System.out.println("大文件写(03版本)生产完毕~!");

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

        System.out.println("大文件写(03版本)总用时:" + (end - begin * 1.0) / 1000 + "s");
    }
}

3.6 对于大文件的操作(07版本)

  • 好处:可以更多的数据
  • 缺点:写数据会慢,消耗内存,可能会发生内存溢出问题
    65536行代码的运行时间:4.488s(根据自身电脑配置,做判断)
    100000行代码的运行时间:6.047s(根据自身电脑配置,做判断)
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;
import java.io.IOException;

public class ExcelService {

    /* excel文件存放路径 */
    String PATH = "G:\\Java\\Excel\\POI\\";

    /**
     * 大文件写(07版本)
     * 注意:创建的象 new XSSFWorkbook();
     * 文件后缀:.xlsx
     * 最大范围:1,048,576
     */
    @Test
    public void write07Big() throws IOException {
        // 程序开始时间
        long begin = System.currentTimeMillis();

        // 1、创建工作簿
        Workbook workbook = new XSSFWorkbook();
        // 2、创建表
        Sheet sheet = workbook.createSheet();
        // 3、创建65536行数据,看看总运行时间
        for (int rowNum = 0; rowNum < 65536; rowNum++) {
            Row row = sheet.createRow(rowNum);
            // 每列生产 0 - 9
            for (int cellNum = 0; cellNum < 10; cellNum++) {
                Cell cell = row.createCell(cellNum);
                cell.setCellValue(cellNum);
            }
        }

        // 5、保存到本地
        FileOutputStream savePath = new FileOutputStream(PATH + "大文件写(07版本).xlsx");

        // 6、将数据写到指定路径
        workbook.write(savePath);

        // 7、刷流、关流
        savePath.flush();

        savePath.close();

        System.out.println("大文件写(07版本)生产完毕~!");

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

        System.out.println("大文件写(07版本)总用时:" + (end - begin * 1.0) / 1000 + "s");
    }
}

3.7 对于大文件操作(Plus版本)

  • 好处:可以写很大的数据,写数据速度快,占用更少的内存
  • 注意:在代码执行的过程中,需要清理临时文件,默认是100条数据保存在内存中,超过这数量,就会写到临时文件~ 想定义默认的数据,可以使用 new SXSSFWorkbook(“数量”);
  • 100000行代码的运行时间:1.579s(根据自身电脑配置,做判断)
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.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.junit.Test;

import java.io.FileOutputStream;
import java.io.IOException;

public class ExcelService {

    /* excel文件存放路径 */
    String PATH = "G:\\Java\\Excel\\POI\\";

    /**
     * 大文件写(plus)
     * 注意:创建的象 new SXSSFWorkbook();
     * 文件后缀:.xlsx
     */
    @Test
    public void write07Big() throws IOException {
        // 程序开始时间
        long begin = System.currentTimeMillis();

        // 1、创建工作簿
        SXSSFWorkbook workbook = new SXSSFWorkbook();
        // 2、创建表
        Sheet sheet = workbook.createSheet();
        // 3、创建65536行数据,看看总运行时间
        for (int rowNum = 0; rowNum < 100000; rowNum++) {
            Row row = sheet.createRow(rowNum);
            // 每列生产 0 - 9
            for (int cellNum = 0; cellNum < 10; cellNum++) {
                Cell cell = row.createCell(cellNum);
                cell.setCellValue(cellNum);
            }
        }

        // 5、保存到本地
        FileOutputStream savePath = new FileOutputStream(PATH + "大文件写(plus).xlsx");

        // 6、将数据写到指定路径
        workbook.write(savePath);

        // 7、清楚临时文件
        workbook.dispose();
        // 7、刷流、关流
        savePath.flush();

        savePath.close();

        System.out.println("大文件写(plus)生产完毕~!");

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

        System.out.println("大文件写(plus)总用时:" + (end - begin * 1.0) / 1000 + "s");
    }
}

3.8 POI 读(难点)

如果是07版本的Excel ,只需要将HSSFWorkbook类修改为XSSFWorkbook类。将xls文件修改为xlsx文件

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.joda.time.DateTime;
import org.junit.Test;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Date;

public class ExcelService {

    /**
     * 文件读
     * 注意:创建的象 new HSSFWorkbook();
     * 文件后缀:.xls
     */
    @Test
    public void Reader03() throws IOException {
        // 1、读取文件
        FileInputStream filePath = new FileInputStream("G:\\Java\\Excel\\POI\\文件基本写(03版本).xls");
        // 2、获取工作簿
        HSSFWorkbook workbook = new HSSFWorkbook(filePath);
        // 3、获取表(0表示第一张表)
        Sheet sheet = workbook.getSheetAt(0);
        // 4、获取第一行的数据
        Row row = sheet.getRow(0);
        // 4.1 如果第一行不为空,就继续
        if (row != null) {
            // 4.2 获取每一行多几个字段
            int numberOfCells = row.getPhysicalNumberOfCells();
            for (int cellNum = 0; cellNum < numberOfCells; cellNum++) {
                // 4.3 从头到尾获取字段
                Cell cell = row.getCell(cellNum);
                // 4.3 获取String字段的信息
                String stringCellValue = cell.getStringCellValue();
                System.out.print(stringCellValue + " | ");
            }
        }
        System.out.println();
        // 5、获取下面的数据(问题来了,因为第一行的数据是标题,我知道是字符串,但是下面的数据是数字、日期、布尔等等类型该怎么办呢?这时就只能特判了)
        // 5.1 获取表一共有多少行
        int numberOfRows = sheet.getPhysicalNumberOfRows();
        // 5.2 重复4的步骤,进行特判 (从1开始,是因为第一行是标题)
        for (int rows = 1; rows < numberOfRows; rows++) {
            // 5.3 一行的数据
            Row rowData = sheet.getRow(rows);
            // 5.4 如果一行有数据,就继续
            if (rowData != null) {
                // 5.5 一行有多少个字段
                int numberOfCells = rowData.getPhysicalNumberOfCells();
                for (int cellNum = 0; cellNum < numberOfCells; cellNum++) {
                    // 5.6 获取每个字段
                    Cell cell = rowData.getCell(cellNum);
                    // 5.7 打印当前行和列
                    System.out.print("[" + (rows + 1) + "  " + (cellNum + 1) + "]");
                    // 6、开始特判,字段不为空就开始判断
                    if (cell != null) {
                        // 6.1 字获取段类型
                        CellType cellType = cell.getCellType();
                        // 6.2 创建字符串,用于观看最后字段是什么类型的
                        String str = new String();
                        switch (cellType) {
                            // 6.3 是字符串,就执行
                            case STRING:
                                System.out.print("[String]");
                                str = cell.getStringCellValue();
                                break;
                            // 6.4 是数字,就执行(数字包括日期、数字)
                            case NUMERIC:
                                System.out.print("[numeric]");
                                // 6.4.1 是日期
                                if (HSSFDateUtil.isCellDateFormatted(cell)) {
                                    System.out.print("[日期]");
                                    Date date = cell.getDateCellValue();
                                    str = new DateTime(date).toString("yyyy-MM-dd HH:mm:ss");
                                } else {
                                    System.out.print("[转换字符输出]");
                                    // 6.4.2 是数字
                                    cell.setCellValue(cell.toString());
                                    str = cell.toString();
                                }
                                break;
                            // 6.4.3 是空
                            case BLANK:
                                System.out.print("[blank]");

                                // 6.4.3 是布尔
                            case BOOLEAN:
                                System.out.print("[boolean]");
                                str = String.valueOf(cell.getBooleanCellValue());
                                break;

                            // 6.4.4 是错误
                            case ERROR:
                                System.out.print("[error]");
                                break;
                        }
                        System.out.print("[" + str + "]\n");
                    }
                }
            }

        }
    }
}

3.9 测试结果

Java 实现 Apach POI_第2张图片

第一行:表格标题
下面:是第二行的数据

  • 行 列号
  • 字段类型
  • 字段数据

四、EasyExcel

Java 实现 EasyExcel


五、教程推荐

【狂神说Java】POI及EasyExcel一小时搞定通俗易懂

你可能感兴趣的:(Excel,SpringBoot,集成系列,java,开发语言)