POI 讲解

一、POI 是什么?

Apache POI 是 Apache 基金会提供的一套 Java 操作 Office 文档的开源库,主要支持:

  • Excel(.xls / .xlsx)
  • Word(.doc / .docx)
  • PowerPoint
  • Visio
  • Outlook

其中最常用的就是 Excel 操作

二、为什么要用 POI?

因为在企业开发中,Excel 是最常见的数据交换格式,比如:

  • 导出报表(订单报表、财务报表)
  • 导入数据(批量导入用户、批量导入商品)
  • 模板导出(固定模板 + 动态数据)
  • 数据备份
  • 批量生成合同、发票等文档

Java 本身没有提供操作 Excel 的能力,所以必须依赖 POI。

三、POI 支持的 Excel 格式

POI 支持两种 Excel 格式:

  1. HSSF ------ 操作 .xls(Excel 97-2003)

    • 最多 65536 行
    • 最多 256 列
  2. XSSF ------ 操作 .xlsx(Excel 2007+)

    • 最多 1,048,576 行
    • 最多 16,384 列
    • 推荐使用
  3. SXSSF ------ 大数据量导出(百万级)

    • 基于 XSSF,但使用 流式处理
    • 适合导出几十万、几百万行数据
    • 内存占用极低

四、POI 核心对象模型

POI 操作 Excel 的核心对象如下(非常重要):

  • Workbook(工作簿) → 对应整个 Excel 文件 ,创建 / 读取 Excel 的入口对象
    • XSSF 格式:XSSFWorkbook workbook = new XSSFWorkbook();
  • Sheet(工作表) → 对应 Excel 里的一个 sheet 页签 ,一个 Workbook 可以创建多个 Sheet
    • 创建:Sheet sheet = workbook.createSheet("用户报表");
    • 获取:Sheet sheet = workbook.getSheetAt(0); // 获取第一个 sheet
  • Row(行) → 对应 Sheet 中的一行数据 ,行索引从0开始(0 是表头行)
    • 创建:Row row = sheet.createRow(0); // 创建第 1 行
    • 获取:Row row = sheet.getRow(1); // 获取第 2 行
  • Cell(单元格) → 对应 Row 中的一个单元格 ,列索引从0开始
    • 创建:Cell cell = row.createCell(0); // 创建当前行的第 1 列单元格
    • 获取:Cell cell = row.getCell(1); // 获取当前行的第 2 列单元格
  • 辅助对象:CellStyle(单元格样式)、Font(字体样式)→ 用于设置单元格的字体、颜色、对齐方式、边框等
  • 核心层级关系:Workbook → Sheet → Row → Cell

五、POI 读写 Excel 实战

引入依赖:

java 复制代码
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>4.1.2</version>
</dependency>

写入 Excel(导出)

java 复制代码
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

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

public class ExcelWriter {
    public static void main(String[] args) throws IOException {
        // 1. 创建 Workbook
        Workbook workbook = new XSSFWorkbook();

        // 2. 创建 Sheet
        Sheet sheet = workbook.createSheet("用户列表");

        // 3. 创建表头行
        Row headerRow = sheet.createRow(0);
        headerRow.createCell(0).setCellValue("ID");
        headerRow.createCell(1).setCellValue("姓名");
        headerRow.createCell(2).setCellValue("年龄");

        // 4. 写入数据
        Object[][] data = {
                {1, "张三", 20},
                {2, "李四", 22},
                {3, "王五", 25}
        };

        int rowIndex = 1;
        for (Object[] rowData : data) {
            Row row = sheet.createRow(rowIndex++);
            row.createCell(0).setCellValue((Integer) rowData[0]);
            row.createCell(1).setCellValue((String) rowData[1]);
            row.createCell(2).setCellValue((Integer) rowData[2]);
        }

        // 5. 输出到文件
        try (FileOutputStream outputStream = new FileOutputStream("users.xlsx")) {
            workbook.write(outputStream);
        }

        System.out.println("Excel 生成成功!");
    }
}

读取 Excel(导入)

java 复制代码
import org.apache.poi.ss.usermodel.*;

import java.io.FileInputStream;
import java.io.IOException;

public class ExcelReader {
    public static void main(String[] args) throws IOException {
        // 1. 读取文件
        try (FileInputStream inputStream = new FileInputStream("users.xlsx");
             Workbook workbook = new XSSFWorkbook(inputStream)) {

            // 2. 获取 Sheet
            Sheet sheet = workbook.getSheetAt(0);

            // 3. 遍历行
            for (Row row : sheet) {
                // 4. 遍历单元格
                for (Cell cell : row) {
                    // 根据单元格类型读取数据
                    switch (cell.getCellType()) {
                        case STRING:
                            System.out.print(cell.getStringCellValue() + "\t");
                            break;
                        case NUMERIC:
                            System.out.print(cell.getNumericCellValue() + "\t");
                            break;
                        case BOOLEAN:
                            System.out.print(cell.getBooleanCellValue() + "\t");
                            break;
                        default:
                            System.out.print("\t");
                    }
                }
                System.out.println();
            }
        }
    }
}
相关推荐
咩咩啃树皮5 小时前
第40篇:Vue3组件化开发精讲——组件拆分、复用、父子通信、工程化架构
java·前端·架构
鱟鲥鳚6 小时前
Spring Boot 集成 LangChain4j:从模型调用到 Tool Calling(Demo版)
java·spring boot
大模型码小白7 小时前
【Python零基础教程】继承、多态与魔法函数:面向对象编程三大核心特性详解
java·大数据·开发语言·人工智能·python·ai编程
腾渊信息科技公司8 小时前
Spring Boot对接MES实战:视觉检测数据自动同步方案
java·人工智能·spring boot·后端·计算机视觉·ai·软件需求
爱笑的源码基地9 小时前
高并发 Redis 缓存门诊HIS系统源码,含财务统计药房进销存
java·程序·门诊系统·诊所系统·云诊所源码
wuqingshun3141599 小时前
TCP超时重传机制是为了解决什么问题?
java
莫逸风11 小时前
【AgentScope 2.0】 0. 学习指南
java·llm·agent·agentscope
隔窗听雨眠12 小时前
Spring Boot在云原生时代的编程范式革新研究
spring boot·后端·云原生
z1234567898612 小时前
2026最新两款AI编程工具深度对比实测
java·数据库·ai编程
yaoxin52112313 小时前
470. Java 反射 - Member 接口与 AccessFlag
java·开发语言·python