Apache POI XSSFWorkbook 和 SXSSFWorkbook 的区别

解决方案:将 XSSFWorkbook 转换为 SXSSFWorkbook 避免 OOM

1. 为什么 SXSSFWorkbook 能解决 OOM?
  • XSSFWorkbook :将整个 Excel 文件加载到内存,数据量较大时(如超过 10 万行)会导致 内存溢出(OOM)
  • SXSSFWorkbook (Streaming Version of XSSFWorkbook):
    • 仅保留最近 N 行 (由 rowAccessWindowSize 参数控制)在内存中,其余数据写入临时文件。
    • 通过 磁盘空间换内存空间,避免 OOM。
    • 适用于大数据量导出(百万级数据)。

2. 如何将 XSSFWorkbook 转换为 SXSSFWorkbook
场景 1:导出 Excel(新建文件)
复制代码

java

复制代码
`// 直接使用 SXSSFWorkbook 替代 XSSFWorkbook
try (SXSSFWorkbook wb = new SXSSFWorkbook(100);  // 保留最近 100 行在内存
     ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
    
    // 创建 Sheet
    SXSSFSheet sheet = wb.createSheet("Sheet1");
    
    // 写入表头(同 XSSFWorkbook)
    XSSFRow headerRow = (XSSFRow) sheet.createRow(0);
    headerRow.createCell(0).setCellValue("Name");
    headerRow.createCell(1).setCellValue("Age");
    
    // 写入数据(循环写入)
    for (int i = 0; i < 100000; i++) {
        XSSFRow dataRow = (XSSFRow) sheet.createRow(i + 1);
        dataRow.createCell(0).setCellValue("User" + i);
        dataRow.createCell(1).setCellValue(20 + i);
        
        // 可选:手动刷新行到磁盘(减少内存占用)
        if (i % 1000 == 0) {
            ((SXSSFSheet) sheet).flushRows(100); // 保留最近 100 行
        }
    }
    
    wb.write(outputStream);
    return outputStream.toByteArray();
} catch (IOException e) {
    e.printStackTrace();
    return null;
}`
场景 2:读取大 Excel 文件(避免 OOM)

如果需要读取大 Excel 文件并处理,建议直接使用 XSSFReader(SAX 模式)EasyExcel ,因为 SXSSFWorkbook 主要用于 写入 ,而非读取。

但若必须用 SXSSFWorkbook 处理大文件,可以分段读取:

复制代码

java

复制代码
`try (XSSFWorkbook xssfWorkbook = new XSSFWorkbook(new FileInputStream("large_file.xlsx"));
     SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook(xssfWorkbook, 100)) {
    
    SXSSFSheet sheet = (SXSSFSheet) sxssfWorkbook.getSheetAt(0);
    for (Row row : sheet) {
        // 处理每一行(注意:SXSSFWorkbook 读取时可能已丢失部分行,因为它们被写入磁盘)
        System.out.println(row.getCell(0).getStringCellValue());
    }
} catch (IOException e) {
    e.printStackTrace();
}`

⚠️ 注意SXSSFWorkbook 读取时可能无法访问所有行(因为部分行已被写入临时文件),因此 读取大文件建议用 XSSFReaderEasyExcel


3. 关键优化点
  1. 设置 rowAccessWindowSize

    复制代码

    java

    复制代码
    `SXSSFWorkbook wb = new SXSSFWorkbook(100); // 内存中保留 100 行`
    • 值越小,内存占用越低,但磁盘 I/O 越频繁。
    • 默认值是 100,可根据数据量调整(如 1000)。
  2. 手动调用 flushRows()

    复制代码

    java

    复制代码
    `((SXSSFSheet) sheet).flushRows(100); // 强制将行写入磁盘`
    • 适用于循环中定期释放内存。
  3. 关闭资源

    复制代码

    java

    复制代码
    `try (SXSSFWorkbook wb = new SXSSFWorkbook(100)) {
        // ...操作
    } // 自动调用 dispose() 删除临时文件`
    • 必须调用 dispose() ,否则临时文件可能残留:

      复制代码

      java

      复制代码
      `wb.dispose(); // 删除临时文件`
  4. 禁用临时文件(仅适用于小数据量)

    复制代码

    java

    复制代码
    `SXSSFWorkbook wb = new SXSSFWorkbook(null, 100, true, true);
    // 最后一个参数 true 表示不生成临时文件(全部保留在内存)`

4. 对比 XSSFWorkbookSXSSFWorkbook
特性 XSSFWorkbook SXSSFWorkbook
内存占用 高(全部数据在内存) 低(仅保留部分行)
适用场景 小数据量(< 10 万行) 大数据量(> 10 万行)
临时文件 生成临时文件(需调用 dispose()
读取大文件 支持 不推荐(可能丢失数据)
性能 稍慢(因磁盘 I/O)

5. 扩展:使用 EasyExcel(阿里开源)

如果项目允许引入第三方库,EasyExcel 是更好的选择:

  • 内存优化:基于 SAX 模式解析 Excel,几乎无内存限制。

  • 简单 API

    复制代码

    java

    复制代码
    `// 写入
    EasyExcel.write("output.xlsx", DemoData.class).sheet("Sheet1").doWrite(dataList);
    
    // 读取
    EasyExcel.read("input.xlsx", DemoData.class, new DemoDataListener()).sheet().doRead();`
  • 官网https://easyexcel.opensource.alibaba.com/


总结

  1. 导出大数据量 Excel :用 SXSSFWorkbook 替代 XSSFWorkbook,并设置 rowAccessWindowSize
  2. 读取大 Excel 文件 :用 XSSFReader(SAX 模式)或 EasyExcel
  3. 及时释放资源 :调用 dispose() 删除临时文件。
  4. 终极方案 :考虑 EasyExcel 进一步简化代码并提升性能。

通过以上优化,可彻底解决 XSSFWorkbook 导致的 OOM 问题!

相关推荐
—Miss. Z—11 小时前
Power Query数据分类整合
excel
xifangge202514 小时前
PHP 错误日志在哪里看?Apache / Nginx / PHP-FPM 一次讲清
nginx·php·apache
开开心心就好16 小时前
系统管理工具,多功能隐私清理文件粉碎工具
java·网络·windows·r语言·电脑·excel·symfony
潇凝子潇19 小时前
Apache Kafka 跨集群复制实现方案
分布式·kafka·apache
sinat_3751122619 小时前
abap excel上传
excel·上传·sap·abap
·云扬·20 小时前
【实操教程】Excel文件转CSV并导入MySQL的完整步骤
android·mysql·excel
城数派20 小时前
2019-2025年各区县逐月新房房价数据(Excel/Shp格式)
大数据·数据分析·excel
Elieal20 小时前
EasyExcel 实现 Excel 导入导出
java·excel
大厂技术总监下海1 天前
数据湖加速、实时数仓、统一查询层:Apache Doris 如何成为现代数据架构的“高性能中枢”?
大数据·数据库·算法·apache