Administrator 12 阅读 面试

POI 与 SXSSF 流式导出对比


面试口述版(优先背这个)

问:POI 和 SXSSF 流式导出有什么区别?

答:

Apache POI 是 Java 操作 Excel 的主流库。我们平时说的区别,主要是它里面两种写 .xlsx 的方式:

  • XSSF:普通方式,把整个工作簿加载到内存里操作。
  • SXSSF:流式方式,专门用来导出大数据量。

核心区别是内存占用和写入方式:

  1. XSSF 数据全部在内存,数据量一大就容易 OOM,适合几万行以内、样式比较复杂的场景。
  2. SXSSF 采用滑动窗口机制,默认内存里只保留最近 100 行,更早的行会刷到磁盘临时文件。所以内存占用很低,适合导出几十万、上百万行的数据。

代价是 SXSSF 必须按顺序一行行写,写过的行不能再回头修改,部分高级功能也受限。

我们项目里如果导出数据量比较大,会优先用 SXSSF;数据量小、样式要求高,就用普通 XSSF。

使用 SXSSF 时要注意两点:

  • 导出结束后调用 dispose() 清理临时文件;
  • 窗口大小要根据实际情况调整,太小影响功能,太大内存优势就没了。

一句话总结:XSSF 功能全但吃内存,SXSSF 省内存但只能顺序写,大数据量导出优先用 SXSSF。


详细对比

1. 基本概念

名称 全称 说明
POI Apache POI Java 操作 Microsoft 文档的开源库
HSSF Horrible Spreadsheet Format 操作 .xls(Excel 97-2003)
XSSF XML Spreadsheet Format 操作 .xlsx(Excel 2007+),普通方式
SXSSF Streaming XSSF XSSF 的流式版本,低内存导出大数据量

日常说的「POI 和 SXSSF 的区别」,实际是在对比 XSSF(普通) 和 SXSSF(流式)。


2. 核心区别表

对比点 XSSF(普通 POI) SXSSF(流式导出)
内存占用 很高,数据全在内存 很低,只保留滑动窗口内的行
适用数据量 较小(一般几万行以内) 较大(几十万、上百万行)
原理 整个工作簿在内存中构建 已写完的行刷到磁盘临时文件,内存只保留最近 N 行
写入方式 可随机写、反复修改任意单元格 必须顺序写,写过的行基本不能再改
功能完整性 支持几乎所有 Excel 特性 部分高级功能受限(复杂样式、公式、随机访问等)
性能表现 数据量大时易 OOM 或变慢 内存稳定,适合大数据量
临时文件 无 会生成磁盘临时文件,需手动清理

3. 原理简单说明

XSSF:

  • 把整个 Excel 当成内存中的大对象来操作。
  • 行、单元格、样式全都在堆内存里。
  • 数据量上升后,内存会线性增长,容易撑爆 JVM。

SXSSF:

  • 引入「滑动窗口」(rowAccessWindowSize)。
  • 默认只在内存保留最近 100 行。
  • 超出窗口的行会被序列化到磁盘临时文件,从内存移除。
  • 因此内存占用基本稳定,适合大数据量导出。

4. 代码对比

普通 XSSF:

Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("数据");

// 可以随意创建、修改任意行
Row row = sheet.createRow(10000);
row.createCell(0).setCellValue("任意位置都能写");

SXSSF 流式:

// 内存中只保留 100 行,超出的刷到磁盘
SXSSFWorkbook workbook = new SXSSFWorkbook(100);
Sheet sheet = workbook.createSheet("数据");

for (int i = 0; i < 1_000_000; i++) {
    Row row = sheet.createRow(i);   // 必须按顺序写
    row.createCell(0).setCellValue("第" + i + "行");
}

// 写完后必须清理临时文件
workbook.dispose();
workbook.close();

5. 使用场景建议

场景 推荐方式
数据量小(几万行以内),需要复杂样式、合并单元格、图表等 XSSF
数据量大(十万、百万行),主要是列表导出 SXSSF
既要大数据量,又要部分复杂样式 SXSSF + 适当增大窗口,或分批导出
导出后还需要大量随机修改单元格 不适合 SXSSF,考虑 XSSF 或分批处理

6. SXSSF 使用注意点

  1. 必须顺序写行,不能先写第 100 行再回头写第 1 行。
  2. 导出结束后一定要调用 workbook.dispose(),删除临时文件,避免磁盘被占满。
  3. 窗口大小(rowAccessWindowSize)一般设为 100~500。太小可能影响某些操作,太大则内存优势下降。
  4. 部分功能受限:对已刷出内存的行,不支持富文本、某些绘图、评论等高级特性。
  5. 大文件导出时,建议直接写入 ServletOutputStream 或文件流,避免先生成完整文件再下载。

7. 一句话总结

  • XSSF:功能全、内存高,适合小数据、复杂样式。
  • SXSSF:内存低、顺序写,适合大数据量列表导出。

项目中导出超过十万行时,优先考虑 SXSSF;数据量不大且样式要求高,用普通 XSSF 即可。