POI 与 SXSSF 流式导出对比
面试口述版(优先背这个)
问:POI 和 SXSSF 流式导出有什么区别?
答:
Apache POI 是 Java 操作 Excel 的主流库。我们平时说的区别,主要是它里面两种写 .xlsx 的方式:
- XSSF:普通方式,把整个工作簿加载到内存里操作。
- SXSSF:流式方式,专门用来导出大数据量。
核心区别是内存占用和写入方式:
- XSSF 数据全部在内存,数据量一大就容易 OOM,适合几万行以内、样式比较复杂的场景。
- 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 使用注意点
- 必须顺序写行,不能先写第 100 行再回头写第 1 行。
- 导出结束后一定要调用
workbook.dispose(),删除临时文件,避免磁盘被占满。 - 窗口大小(
rowAccessWindowSize)一般设为 100~500。太小可能影响某些操作,太大则内存优势下降。 - 部分功能受限:对已刷出内存的行,不支持富文本、某些绘图、评论等高级特性。
- 大文件导出时,建议直接写入
ServletOutputStream或文件流,避免先生成完整文件再下载。
7. 一句话总结
- XSSF:功能全、内存高,适合小数据、复杂样式。
- SXSSF:内存低、顺序写,适合大数据量列表导出。
项目中导出超过十万行时,优先考虑 SXSSF;数据量不大且样式要求高,用普通 XSSF 即可。