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 问题!

相关推荐
TracyDemo10 小时前
excel 透视图怎么进行删除透视图
excel
骆驼爱记录11 小时前
Excel邮件合并嵌入图片技巧
自动化·word·excel·wps·新人首发
avi911112 小时前
Unity Data Excel读取方法+踩坑记;和WPS Excel的一些命令
unity·游戏引擎·excel·wps·data
软件派13 小时前
Apache Paimon终极教程——流批一体存储引擎深度解析(附Flink集成案例+性能调优代码)
apache·性能调优·流批一体·实时数据处理·paimon教程·flink集成·湖仓架构
梦幻通灵13 小时前
Excel多个sheet合并透视表实现方案【持续更新】
excel
开开心心就好14 小时前
键盘映射工具改键位,绿色版设置后重启生效
网络·windows·tcp/ip·pdf·计算机外设·电脑·excel
恬淡如雪14 小时前
Excel接口测试自动化实战
爬虫·python·excel
三水不滴14 小时前
Apache RocketMQ的原理与实践
经验分享·apache·rocketmq
速易达网络15 小时前
linux命令大全
linux·运维·excel
Leisure -_-15 小时前
新建时没有excel选项,如何添加?
excel