Java Excel 处理不再被 OOM 支配:Apache Fesod 百万级数据实战与调优手记

发布时间:2026/8/20 21:58:00
Java Excel 处理不再被 OOM 支配:Apache Fesod 百万级数据实战与调优手记 Java Excel 处理不再被 OOM 支配Apache Fesod 百万级数据实战与调优手记【免费下载链接】fesodFast. Easy. Done. Processing spreadsheets without worrying about large files causing OOM.项目地址: https://gitcode.com/gh_mirrors/fast/fesodApache Fesod孵化中是一个主打高性能、低内存的 Java Excel 处理库专治文件一大就内存溢出的老毛病。这篇文章以一次真实事故开头带你把百万级数据的读写踩坑与调优一次摸清从依赖引入到分批落库都有可以直接抄的结论。事故复盘一张 40 万行的表干掉了 1G 堆先讲个真事。某次线上导出任务业务方要一次性把 40 万行订单明细导成 Excel代码是网上抄的先全查出来再循环 setValue写法。结果凌晨三点报警堆内存 1G 直接被干爆JVM 频繁 Full GC接口超时工单铺了一屏。第二天排查问题根本不在 SQL而在那一行workbook.createSheet()之后把所有行都塞进了内存。40 万行 × 每行几十个单元格加上样式对象内存轻松上 G。这不是某一家公司的个例凡是 Java 写 Excel 的老项目多少都踩过类似的坑。它到底是什么从 FastExcel 到 Apache Fesod 的两年Apache Fesod 的前身是 FastExcel2024 年 10 月开源最初就是奔着处理大文件别 OOM这个目标去的。项目持续迭代后于 2025 年 9 月通过 Apache 基金会孵化器投票9 票赞成、零反对正式成为 Apache 孵化项目仓库也随之移交。名字 Fesod 是 fast easy spreadsheet and other documents 的缩写读作/ˈfɛsɒd/。成为 Apache 孵化项目意味着什么社区治理更规范、提交者机制更透明、代码合规审查更严格也意味着它有长期维护的承诺而不是某个个人开发者哪天弃坑就停更。目前仓库已有 5000 star、20 贡献者对一款工具型项目来说这个起点相当扎实。为什么传统方案会崩三个字全量加载旧方案的问题可以一句话概括全量加载。无论是读还是写都把整个工作表塞进内存再处理数据量和内存占用成正比。文件 100MB内存就要吃掉好几倍文件上 GB直接看运气。Fesod 的思路完全不同读取走 SAX 事件驱动像水管送水一样一行一行地解析 XML内存里永远只存当前正在处理的这一批写入走流式 API写完一批就把数据冲刷到临时文件内存占用和文件总大小基本脱钩。你可以把它的临时文件机制理解成打草稿正稿没写完之前草稿纸随便堆但内存这个桌面永远只摊开一页。15 分钟上手装依赖、写模型、读写各三行先别急着研究内部原理跑通第一个 Demo 只需要三步。第一步pom 里加一行依赖dependency groupIdorg.apache.fesod/groupId artifactIdfesod-sheet/artifactId version2.0.2-incubating/version /dependencyGradle 对应implementation org.apache.fesod:fesod-sheet:2.0.2-incubating。该版本支持 JDK 8 到 JDK 25老项目基本都能直接引。它底层依赖 Apache POI 5.5.1、Apache Commons CSV 1.14.1 和 Ehcache 3.9.11如果你的项目里已经有 POI 相关依赖记得手动排除避免版本冲突——这是新手最容易踩的第一个坑。第二步用注解把列名映射到字段一个普通 POJO加两个注解就完成了模型定义public class DemoData { ExcelProperty(订单号) private String orderId; ExcelProperty(金额) private Double amount; ExcelIgnore private String 不入Excel的字段; }ExcelProperty决定表头名称和字段映射ExcelIgnore负责排除无关字段。读写共用这一套模型头都不用重写。第三步读与写各一条链式调用读文件三行FesodSheet.read(fileName, DemoData.class, new PageReadListener(list - { // 每 100 行回调一次在这里落库 saveBatch(list); })).sheet().doRead();写文件也是三行FesodSheet.write(fileName, DemoData.class) .sheet(订单导出) .doWrite(dataList);PageReadListener内置按页分批的能力默认 100 行一批新手不需要自己写监听器完整示例在 fesod-examples/fesod-sheet-examples/ 的 quickstart 包下跑一遍就知道输出长什么样。深水区百万行导出先学会边写边丢上面的doWrite(list)适合十万行以内的场景。真要碰百万行必须换ExcelWriter它的核心思想是分批写、边写边丢。用 ExcelWriter 分批写别一把梭try (ExcelWriter writer FesodSheet.write(fileName, DemoData.class).build()) { WriteSheet sheet FesodSheet.writerSheet(导出).build(); for (int i 0; i 1000; i) { writer.write(nextBatch(100), sheet); // 每批 100 行循环 1000 次 } }每调一次write()数据就被冲刷到临时 XML 里内存里只保留当前批次。配合 try-with-resources资源自动释放不会出现导出完文件句柄还挂着的毛病。官方大文件写指南见 website/docs/sheet/advanced/large-file.md。临时文件压缩磁盘告急时的救命开关流式写入的代价是临时文件占磁盘。如果磁盘紧张可以注册一个WorkbookWriteHandler在afterWorkbookCreate里给底层的SXSSFWorkbook打开压缩开关if (workbook instanceof SXSSFWorkbook) { ((SXSSFWorkbook) workbook).setCompressTempFiles(true); }代价是 CPU 多花一点换来磁盘占用大幅下降。临时文件目录位置可以通过FileUtils.getPoiFilesPath()拿到监控脚本定期看看它的大小心里有数。百万行导入监听器按页接货落库走批导入侧同理别在监听器里逐条 insert。正确姿势是攒够一批再批量入库public class OrderReadListener implements ReadListenerDemoData { private final ListDemoData cache new ArrayList(500); Override public void invoke(DemoData data, AnalysisContext context) { cache.add(data); if (cache.size() 500) { saveBatch(cache); cache.clear(); } } Override public void doAfterAllAnalysed(AnalysisContext context) { saveBatch(cache); } }批大小500、1000 还是 2000取决于你每行字段的宽度和可用堆内存没有万能值压测后取一个内存不涨、GC 不频繁的平衡点即可。排坑清单五个高频问题一次说清读着读着 OOM先看是不是用了doReadAll()之类的全量 API换成监听器流式读取。临时文件把磁盘塞满了开压缩开关或者把FileUtils.getPoiFilesPath()指到空间充足的盘。项目里已有 POI一跑就冲突排除掉旧版 POI 相关 jar让 fesod-sheet 统一管理版本。从 FastExcel 迁移过来要改多少代码主要改两处依赖坐标换成org.apache.fesod:fesod-sheet包名从cn.idev.excel换成org.apache.fesod.sheet入口类统一换成FesodSheet。API 几乎一一对应老项目可以分阶段迁移详细对照表在 website/docs/migration/from-fastexcel.md。自定义类型怎么转实现ConverterT接口重写convertToJavaData和convertToExcelData两个方法即可日期、金额、枚举都能接管参考 converters 目录下的现成实现。它和同类工具怎么选一句话结论传统 POI 功能最全但内存最吃紧适合小文件和对格式控制极度苛刻的场景EasyExcel 生态成熟是很多老项目的现状Fesod 作为后起之秀优势在流式架构、低内存占用和 Apache 治理下的长期稳定性且与 EasyExcel 系 API 高度兼容迁移成本低。如果你的核心痛点是大数据量 不想重写业务代码选它基本不会后悔。社区与下一步Apache 孵化意味着什么从 2024 年开源到如今star 曲线一路陡峭向上社区的认可度是实打实的。进入孵化器之后项目在代码合规、发布流程、贡献者培养上都会按 Apache 标准运转对使用者来说是多了一层不会突然断更的保障。最后说句实在话处理大 Excel 这件事技术难度不在 API而在内存心智模型——只要记住流式读取、分批写入、按页落库这十二个字再大的文件也翻不了车。想动手试的克隆仓库地址是https://gitcode.com/gh_mirrors/fast/fesodmvn clean install之后直接跑 examples 模块从读一个 demo.xlsx 开始比看十篇教程都管用。【免费下载链接】fesodFast. Easy. Done. Processing spreadsheets without worrying about large files causing OOM.项目地址: https://gitcode.com/gh_mirrors/fast/fesod创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考