浅谈 Apache POI:XSSFWorkbook 的原理与实践(Java 操作 Excel 实践指南)

在企业开发中,Excel 几乎无处不在

  • 数据导入(批量导入用户、工单、设备)
  • 报表导出(运营报表、财务报表)
  • 数据交换(系统之间通过 Excel 交互)

如果使用 Java 开发系统,最常见的解决方案就是:

Apache POI

而在 POI 中,最核心的类之一就是:

java 复制代码
org.apache.poi.xssf.usermodel.XSSFWorkbook

下面我们详细展开。


一、Apache POI 是什么

Apache POI 是 Apache 开源的一个 Java 操作 Office 文件的库

支持:

Office文件 POI组件
Excel 2003 .xls HSSF
Excel 2007+ .xlsx XSSF
Word .docx XWPF
PowerPoint XSLF

本文重点介绍:

java 复制代码
XSSFWorkbook

含义:

复制代码
XSSF = XML Spreadsheet Format

即:

用于操作 Excel .xlsx 文件的 Java API


二、Excel 的对象结构

Excel 文件其实是一个 层级结构

复制代码
Workbook(工作簿)
 ├── Sheet(工作表)
 │     ├── Row(行)
 │     │     ├── Cell(单元格)

Apache POI 的类结构:

Excel概念 POI类
工作簿 XSSFWorkbook
工作表 XSSFSheet
XSSFRow
单元格 XSSFCell

对象关系:

复制代码
XSSFWorkbook
    └── XSSFSheet
          └── XSSFRow
                └── XSSFCell

因此:

XSSFWorkbook 就是整个 Excel 文件的 Java 对象表示。


三、Excel 文件的真实结构(核心原理)

大家或许不知道:

.xlsx 本质上是一个 ZIP 文件。

我们可以直接解压:

复制代码
example.xlsx

得到:

复制代码
example.xlsx
 ├── [Content_Types].xml
 ├── _rels/
 ├── xl/
 │    ├── workbook.xml
 │    ├── worksheets/
 │    │      ├── sheet1.xml
 │    │      ├── sheet2.xml
 │    ├── styles.xml
 │    ├── sharedStrings.xml

核心结构:

文件 作用
workbook.xml 工作簿信息
sheet.xml 工作表
sharedStrings.xml 字符串池
styles.xml 样式

POI 的工作流程:

复制代码
Excel文件
    ↓
解压 ZIP
    ↓
解析 XML
    ↓
构建 Java 对象

最终形成:

复制代码
XSSFWorkbook
 └── XSSFSheet
      └── XSSFRow
           └── XSSFCell

四、引入 Apache POI 依赖

Maven 依赖:

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

核心组件:

复制代码
poi
poi-ooxml
xmlbeans
commons-compress

五、读取 Excel(最常见场景)

典型场景:

  • 用户上传 Excel
  • 解析数据
  • 写入数据库

示例 Excel:

复制代码
users.xlsx

ID | Name | Age
1  | Tom  | 20
2  | Jack | 22

Java 读取代码:

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

import java.io.FileInputStream;

public class ExcelReader {

    public static void main(String[] args) throws Exception {

        FileInputStream fis = new FileInputStream("users.xlsx");

        XSSFWorkbook workbook = new XSSFWorkbook(fis);

        Sheet sheet = workbook.getSheetAt(0);

        for (Row row : sheet) {

            for (Cell cell : row) {

                System.out.print(cell.toString() + "  ");
            }

            System.out.println();
        }

        workbook.close();
        fis.close();
    }
}

输出:

复制代码
ID Name Age
1 Tom 20
2 Jack 22

六、Excel 精确读取

实际开发中需要:

  • 跳过标题
  • 判断类型
  • 处理空值

示例:

java 复制代码
for (int i = 1; i <= sheet.getLastRowNum(); i++) {

    Row row = sheet.getRow(i);

    if (row == null) {
        continue;
    }

    Cell idCell = row.getCell(0);
    Cell nameCell = row.getCell(1);
    Cell ageCell = row.getCell(2);

    int id = (int) idCell.getNumericCellValue();
    String name = nameCell.getStringCellValue();
    int age = (int) ageCell.getNumericCellValue();

    System.out.println(id + " " + name + " " + age);
}

输出:

复制代码
1 Tom 20
2 Jack 22

七、创建 Excel 文件

除了读取,还可以 生成 Excel 报表

示例:

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

import java.io.FileOutputStream;

public class ExcelWriter {

    public static void main(String[] args) throws Exception {

        XSSFWorkbook workbook = new XSSFWorkbook();

        Sheet sheet = workbook.createSheet("Users");

        Row header = sheet.createRow(0);

        header.createCell(0).setCellValue("ID");
        header.createCell(1).setCellValue("Name");
        header.createCell(2).setCellValue("Age");

        Row row1 = sheet.createRow(1);
        row1.createCell(0).setCellValue(1);
        row1.createCell(1).setCellValue("Tom");
        row1.createCell(2).setCellValue(20);

        FileOutputStream fos = new FileOutputStream("users.xlsx");

        workbook.write(fos);

        fos.close();
        workbook.close();
    }
}

生成 Excel:

复制代码
users.xlsx

ID | Name | Age
1  | Tom  | 20

八、SpringBoot Excel 导出接口

真实系统中,通常通过 HTTP 下载 Excel

示例:

java 复制代码
@GetMapping("/export")
public void export(HttpServletResponse response) throws Exception {

    XSSFWorkbook workbook = new XSSFWorkbook();
    Sheet sheet = workbook.createSheet("Users");

    Row header = sheet.createRow(0);
    header.createCell(0).setCellValue("ID");
    header.createCell(1).setCellValue("Name");

    Row row = sheet.createRow(1);
    row.createCell(0).setCellValue(1);
    row.createCell(1).setCellValue("Tom");

    response.setContentType(
        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");

    response.setHeader(
        "Content-Disposition",
        "attachment;filename=users.xlsx");

    workbook.write(response.getOutputStream());

    workbook.close();
}

浏览器会下载:

复制代码
users.xlsx

九、大文件 Excel 的内存问题

如果 Excel 很大:

复制代码
100万行

使用XSSFWorkbook会全部加载到内存,可能导致:

复制代码
OutOfMemoryError

原因:

复制代码
POI 会把所有 Cell 对象加载到 JVM

十、大文件解决方案:SXSSFWorkbook

POI 提供了:

复制代码
SXSSFWorkbook

特点:

特点 说明
流式写入 不全部加载
低内存 适合百万级
滑动窗口 自动清理

示例:

java 复制代码
import org.apache.poi.xssf.streaming.SXSSFWorkbook;

SXSSFWorkbook workbook = new SXSSFWorkbook(100);

含义:

复制代码
只保留 100 行在内存

生成百万数据:

java 复制代码
for (int i = 0; i < 1000000; i++) {

    Row row = sheet.createRow(i);

    row.createCell(0).setCellValue(i);
}

十一、Excel 导入最佳实践

生产环境建议:

1 跳过空行

java 复制代码
if (row == null) {
    continue;
}

2 判断单元格类型

java 复制代码
switch (cell.getCellType()) {

    case STRING:
        value = cell.getStringCellValue();
        break;

    case NUMERIC:
        value = cell.getNumericCellValue();
        break;
}

3 统一读取工具

建议封装:

java 复制代码
public static String getCellValue(Cell cell)

避免大量判断。


十二、XSSFWorkbook vs HSSFWorkbook

Excel版本 文件格式
HSSFWorkbook Excel 2003 .xls
XSSFWorkbook Excel 2007+ .xlsx

区别:

特点 HSSF XSSF
最大行 65536 1048576
最大列 256 16384
文件格式 二进制 XML

现代系统 基本全部使用 XSSFWorkbook


十三、总结

XSSFWorkbook 的本质:

Excel .xlsx 文件在 Java 中的对象表示。

核心结构:

复制代码
XSSFWorkbook
    ↓
XSSFSheet
    ↓
XSSFRow
    ↓
XSSFCell

常见用途:

场景 说明
Excel 导入 解析数据
Excel 导出 生成报表
数据交换 系统间导入导出

关键注意点:

  • 大文件使用 SXSSFWorkbook
  • 注意 Cell 类型判断
  • 建议封装 读取工具类
相关推荐
沙雕不是雕又菜又爱玩2 小时前
基于springboot的超市收银系统
java·spring boot·intellij-idea
SunnyDays10112 小时前
使用 Java 高效删除 Excel 空白行与空白列
java·删除 excel 空白行·删除 excel 空白列
笨手笨脚の2 小时前
Java 性能优化
java·jvm·数据库·性能优化·分布式锁·分布式事务·并发容器
l软件定制开发工作室2 小时前
Spring开发系列教程(32)——Spring Boot开发
java·spring boot·后端·spring
DolphinScheduler社区2 小时前
Apache DolphinScheduler 3.4.1 发布,新增任务分发超时检测
java·数据库·开源·apache·海豚调度·大数据工作流调度
黑眼圈子2 小时前
Java正则表达式基础知识
java·开发语言·正则表达式
iPadiPhone2 小时前
性能优化的“快车道”:Spring @Async 注解深度原理与大厂实战
java·后端·spring·面试·性能优化
彭于晏Yan2 小时前
JsonProperty注解的access属性
java·spring boot
Mr.朱鹏2 小时前
分布式-redis集群架构
java·redis·分布式·后端·spring·缓存·架构