在java项目中,我们经常使用Apache POI的包导出Excel文件,但是在创建Workbook的时候,有三种选型HSSFWorkbook、XSSFWorkbook、SXSSFWorkbook可以选择,本文总结一下这三个实现类的区别。

在Apache POI中,Workbook接口 代表一个Excel工作簿(即一个Excel文件)。针对不同版本的Excel文件,POI提供了三个主要的实现类:
| 实现类 | 支持的文件格式 | 对应Excel版本 | 文件扩展名 |
|---|---|---|---|
| HSSFWorkbook | HSSF (Horrible SpreadSheet Format) | Excel 97-2003 | .xls |
| XSSFWorkbook | XSSF (XML SpreadSheet Format) | Excel 2007+ | .xlsx |
| SXSSFWorkbook | 基于XSSF的流式扩展 | Excel 2007+ | .xlsx |
SXSSFWorkbook
三个类的API设计高度一致,切换起来非常方便:
import org.apache.poi.hssf.usermodel.HSSFWorkbook;import org.apache.poi.xssf.usermodel.XSSFWorkbook;import org.apache.poi.xssf.streaming.SXSSFWorkbook;// 使用HSSFWorkbook创建.xls文件Workbook workbook = new HSSFWorkbook();// 使用XSSFWorkbook创建.xlsx文件Workbook workbook = new XSSFWorkbook();// 使用SXSSFWorkbook创建.xlsx文件(低内存模式)Workbook workbook = new SXSSFWorkbook();
HSSFWorkbook是POI中最古老的实现,对应的是Excel 97-2003版本的二进制格式(.xls)。
主要特点:
所有数据全部加载到内存中适用场景:
随着Excel 2007推出新的OpenXML格式(.xlsx),POI推出了XSSFWorkbook来支持这种基于XML的新格式。
主要特点:
所有数据全部加载到内存中,内存占用是HSSFWorkbook的2-7倍适用场景:
从POI 3.8版本开始,推出了基于XSSF的流式实现SXSSFWorkbook,专门为了解决大数据量导出时的内存溢出问题。
主要特点:
默认只在内存中保留100行,超出的行会刷新到磁盘临时文件中功能限制(重要!):
由于数据被刷新到磁盘,以下功能无法使用:
autoSizeColumn() - 自动调整列宽cloneSheet() - 克隆工作表getRow()可能返回null)shiftColumns() - 列位移操作适用场景:
口说无凭,我们来看一组权威的性能测试数据(来自Baeldung的JMH基准测试):
执行时间对比(单位:毫秒)
| 行数 | HSSFWorkbook | XSSFWorkbook | SXSSFWorkbook |
|---|---|---|---|
| 2,500 | 73 | 2,658 | 296 |
| 10,000 | 347 | 10,994 | 1,808 |
| 20,000 | 754 | 21,733 | 3,751 |
| 40,000 | 1,455 | 42,331 | 7,342 |
内存消耗对比(单位:MB)
| 行数 | HSSFWorkbook | XSSFWorkbook | SXSSFWorkbook |
|---|---|---|---|
| 2,500 | 828 | 1,871 | 258 |
| 10,000 | 1,268 | 4,136 | 209 |
| 20,000 | 1,766 | 7,443 | 209 |
| 40,000 | 1,475 | 10,119 | 210 |
从数据中可以清晰看到:
开始选型 ↓是否需要输出.xls格式? ├─ 是 → 数据量<6.5万行? → 是 → HSSFWorkbook │ → 否 → 无法满足,考虑分批导出或升级格式 ↓是否需要完整的Excel功能(样式、公式、图表等)? ├─ 是 → 数据量<10万行且内存充足? → 是 → XSSFWorkbook │ → 否 → 考虑分批写入+ XSSFWorkbook ↓是否需要处理超大数据量(>10万行)? ├─ 是 → 能否接受功能限制? → 是 → SXSSFWorkbook │ → 否 → 考虑EasyExcel或分批导出 ↓默认选择 → XSSFWorkbook(常规场景)
场景1:常规报表导出(几千到几万行)
// 推荐使用XSSFWorkbook,功能完整,开发简单try (Workbook workbook = new XSSFWorkbook()) { // 正常的样式、公式处理}场景2:百万级数据导出,无需复杂样式
// SXSSFWorkbook是最佳选择SXSSFWorkbook workbook = new SXSSFWorkbook(100); // 设置内存窗口大小为100try { // 分批写入数据 for (...) { Row row = sheet.createRow(...); // 填充数据 }} finally { // 务必清理临时文件 workbook.dispose(); workbook.close();}场景3:需要复杂样式,但数据量也大
这种情况下可以采取折中方案:
如果选择了SXSSFWorkbook,有几个坑需要特别注意:
SXSSFWorkbook workbook = new SXSSFWorkbook();try { // 处理数据...} finally { workbook.dispose(); // 删除临时文件 workbook.close();}// 以下代码会抛出异常sheet.autoSizeColumn(0); // IllegalStateExceptionworkbook.cloneSheet(0); // IllegalStateException
// 窗口大小设置原则:// - 越小,内存占用越低,但功能限制影响越大// - 越大,可用功能越多,但内存占用越高SXSSFWorkbook workbook = new SXSSFWorkbook(500); // 根据实际需求调整
Apache POI的三个Workbook实现类各有千秋,没有绝对的"最好",只有最适合你当前场景的选择。简单总结一下:
在实际项目中,建议根据数据量、功能需求、内存限制这三个维度综合评估。如果数据量真的到了百万级别,且功能需求复杂,也可以考虑阿里开源的EasyExcel,它在POI基础上做了进一步的封装和优化,同样值得关注。
希望这篇文章能帮你彻底搞懂POI的Workbook家族,从此不再为Excel导出发愁!