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

相关推荐
CodeKwang4 小时前
Qt实战:简易Excel表格 | 附完整源码
qt·excel·qtabwidget·qt控件
脸大是真的好~6 小时前
EasyExcel的使用
java·excel
骆驼爱记录9 小时前
Word样式检查器使用指南
自动化·word·excel·wps·新人首发
热爱生活的五柒10 小时前
wps office/word 表格左对齐后 文字前仍有空白,如何解决
excel
程序员敲代码吗12 小时前
在Excel中快速进行精确数据查找的方法
excel
CodeToGym1 天前
【Java 办公自动化】Apache POI 入门:手把手教你实现 Excel 导入与导出
java·apache·excel
码云数智-大飞1 天前
保姆级教程:零基础快速上手 Apache SeaTunnel(原 Waterdrop)
apache
yuluo_YX1 天前
Reactive 编程 - Java Reactor
java·python·apache
qq_297574671 天前
【实战】POI 实现 Excel 多级表头导出(含合并单元格完整方案)
java·spring boot·后端·excel
人良爱编程2 天前
Hugo的Stack主题配置记录03-背景虚化-导航栏-Apache ECharts创建地图
前端·javascript·apache·echarts·css3·html5