1. 概述

Apache POI 是一个开源库,允许我们以编程方式操作 Microsoft Office 文档,包括 Excel 文件。Apache POI 提供了三个不同的类来创建工作簿:HSSFWorkbookXSSFWorkbookSXSSFWorkbook

本文将深入对比这三个类的功能特性,并通过实际测试数据帮助您根据具体场景选择最佳方案。

2. 创建 Excel 文件

在对比之前,先快速回顾如何使用 Apache POI 生成 Excel 文件。首先在 pom.xml 中添加 Apache POIPOI OOXML schema 依赖:

<dependency> 
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId> 
    <version>5.3.0</version> 
</dependency> 
<dependency> 
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId> 
    <version>5.3.0</version> 
</dependency>

创建 Workbook 实例只需调用目标类的构造函数,然后向工作簿写入内容,最后输出到目标流。以下示例使用 XSSFWorkbook 创建包含测试数据的 test.xlsx 文件:

try (Workbook workbook = new XSSFWorkbook();
  OutputStream outputStream = new BufferedOutputStream(new FileOutputStream("test.xlsx"))) {
    Sheet sheet = workbook.createSheet("test");
    sheet.createRow(0).createCell(0).setCellValue("test content");
    workbook.write(outputStream);
}

切换工作簿类非常简单:只需替换 XSSFWorkbook 为其他实现类,后续操作(创建工作表、行、单元格)完全一致。

⚠️ 注意文件扩展名

  • HSSFWorkbook 生成旧版 .xls 格式(Excel 97-2003)
  • XSSFWorkbookSXSSFWorkbook 生成新版 .xlsx 格式(Excel 2007+)

3. 核心特性对比

Apache POI 的三个工作簿类既有共性又有显著差异,下表总结了关键特性:

特性 HSSFWorkbook XSSFWorkbook SXSSFWorkbook
文件格式 .xls (BIFF8 二进制) .xlsx (OpenXML) .xlsx (OpenXML)
单表最大行数 65,536 1,048,576 1,048,576
单表最大列数 256 16,384 16,384
流式处理 ❌ 否 ❌ 否 ✅ 是
内存占用

核心差异

  • HSSFWorkbook 生成旧版二进制格式,适用于兼容性场景
  • XSSFWorkbookSXSSFWorkbook 生成新版 XML 格式
  • HSSFWorkbookXSSFWorkbook非流式工作簿,所有数据驻留内存
  • SXSSFWorkbook流式工作簿,仅保留部分行在内存中

4. SXSSFWorkbook 的功能限制

SXSSFWorkbook 采用流式处理:当内存中的行数达到窗口阈值(默认 100)时,会自动将数据刷新到磁盘。这种机制导致某些功能无法正常使用——踩坑预警

4.1 测试环境搭建

创建测试用例验证受限功能,初始化包含两行数据的 SXSSFWorkbook显式设置窗口大小为 1(实际场景建议更大):

@BeforeEach
void setup() {
    workbook = new SXSSFWorkbook(1);
    sheet = workbook.createSheet("Test Sheet");
    sheet.createRow(0).createCell(0).setCellValue(5);
    sheet.createRow(1).createCell(0).setCellValue(15);
}

4.2 自动调整列宽

自动调整列宽功能会根据单元格内容长度设置列宽,但在流式模式下会失败——因为系统无法获取已刷新行的宽度信息:

@Test
void whenAutoSizeColumnOnSXSSFWorkbook_thenThrowsIllegalStateException() {
    assertThrows(IllegalStateException.class, () -> sheet.autoSizeColumn(0));
}

4.3 克隆工作表

克隆工作表功能需要完整内存数据支持,流式模式下无法实现:

@Test
void whenCloneSheetOnSXSSFWorkbook_thenThrowsIllegalStateException() {
    assertThrows(IllegalStateException.class, () -> workbook.cloneSheet(0));
}

4.4 获取行数据

尝试获取已刷新的行会返回 null

@Test
void whenGetRowOnSXSSFWorkbook_thenReturnNull() {
    Row row = sheet.getRow(0);
    assertThat(row).isNull();
}

⚠️ 如果窗口大小设为 2(未刷新),此测试会返回行对象。

4.5 公式计算

公式计算功能要求相关行在内存中,否则会抛出异常:

@Test
void whenEvaluateFormulaCellOnSXSSFWorkbook_thenThrowsIllegalStateException() {
    Cell formulaCell = sheet.createRow(sheet.getLastRowNum()).createCell(0);
    formulaCell.setCellFormula("SUM(A1:B1)");

    FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator();
    assertThrows(SXSSFFormulaEvaluator.RowFlushedException.class,
      () -> evaluator.evaluateFormulaCell(formulaCell));
}

4.6 列位移操作

列位移需要完整工作表数据支持,流式模式下直接抛出不支持异常:

@Test
void whenShiftColumnsOnSXSSFWorkbook_thenThrowsUnsupportedOperationException() {
    assertThrows(UnsupportedOperationException.class, () -> sheet.shiftColumns(0, 2, 1));
}

5. 性能评估

通过 JMH (Java Microbenchmark Harness) 对执行时间和内存消耗进行量化测试。

5.1 测试方案

创建包含指定行数的工作表,每行 256 列,填充相同文本内容:

Sheet sheet = workbook.createSheet();
for (int n=0;n<iterations;n++) {
    Row row = sheet.createRow(sheet.getLastRowNum()+1);
    for (int c=0;c<256;c++) {
        Cell cell = row.createCell(c);
        cell.setCellValue("abcdefghijklmnopqrstuvwxyz");
    }
}

测试数据量:2,500 / 5,000 / 10,000 / 20,000 / 40,000 行。每组测试执行三次取平均值。

5.2 执行时间对比(毫秒)

行数 HSSFWorkbook XSSFWorkbook SXSSFWorkbook
2,500 73 2,658 296
5,000 174 4,522 612
10,000 347 10,994 1,808
20,000 754 21,733 3,751
40,000 1,455 42,331 7,342

关键发现

  • HSSFWorkbook 速度最快,比 XSSFWorkbook 快约 30 倍
  • XSSFWorkbook 性能最差,数据量越大劣势越明显
  • SXSSFWorkbook 性能居中,但显著优于 XSSFWorkbook

原因分析:二进制 .xls 格式处理复杂度远低于 XML 格式,数据量越大性能差距越悬殊。

5.3 内存消耗对比(MB)

行数 HSSFWorkbook XSSFWorkbook SXSSFWorkbook
2,500 828 1,871 258
5,000 1,070 2,926 212
10,000 1,268 4,136 209
20,000 1,766 7,443 209
40,000 1,475 10,119 210

关键发现

  • HSSFWorkbookXSSFWorkbook 内存消耗随数据量线性增长
  • XSSFWorkbook 内存占用是 HSSFWorkbook 的 2-7 倍
  • SXSSFWorkbook 内存占用稳定在 ~210MB,几乎不受数据量影响

根本原因:流式处理机制使 SXSSFWorkbook 仅保留少量行在内存中,是处理海量数据的理想选择。

6. 总结建议

根据场景选择合适的工作簿实现:

HSSFWorkbook 适用场景

  • 需要兼容旧版 Excel(97-2003)
  • 数据量小(<65k 行)
  • 对性能要求极高

XSSFWorkbook 适用场景

  • 需要完整 Excel 功能支持
  • 数据量中等(内存充足)
  • 不需要流式处理

SXSSFWorkbook 适用场景

  • 处理超大数据集(>100k 行)
  • 内存资源受限
  • 可接受部分功能限制

决策树

  1. 需要兼容旧 Excel? → HSSFWorkbook
  2. 需要完整功能且内存足够? → XSSFWorkbook
  3. 处理大数据且内存有限? → SXSSFWorkbook

原始标题:Comparison of HSSFWorkbook, XSSFWorkbook, and SXSSFWorkbook in Apache POI | Baeldung