资讯动态

Apache Fesod 大文件写入指南:基于 SXSSF 流式 API 的批量写出与临时文件压缩优化

发布时间:2026/10/4 1:48:57 来源:尧图企业网站定制
后端【免费下载链接】fesodFast. Easy. Done. Processing spreadsheets without worrying about large files causing OOM.项目地址https://gitcode.com/gh_mirrors/fast/fesod点击查看免费下载Apache FesodIncubating的 fesod-sheet 模块内置了对大规模数据导出的支持通过封装 Apache POI 的 SXSSF 流式 API可以稳定写出 10 万行以上的 Excel 文件而不会因一次性装载全部数据导致 OOM。本文基于官方文档 Large File Writing 展开讲解批量写入、临时文件压缩、批次大小调优与磁盘占用监控的完整方案并结合仓库源码说明其底层实现原理帮助你直接落地一套可复用的大文件导出代码。为什么写大文件会 OOM导出数据库全量数据、日志分析结果等场景时如果像普通小文件导出那样把全部行一次性加载进内存再doWrite()数据量达到数十万行后内存必然告急。FesodSheet 的做法是内部走 Apache POI 的流式写入模型.xlsx使用 SXSSFWorkbook.xls使用 HSSFWorkbook工作簿只保留最近 N 行的窗口数据其余行先落盘为临时 XML 文件。从源码看这个选择是在 WorkBookUtil.createWorkBook() 中完成的Workbook workbook writeWorkbookHolder.getInMemory() ? new XSSFWorkbook() : new SXSSFWorkbook();当不要求内存内全量缓存getInMemory()为 false时XLSX 统一使用SXSSFWorkbook这也是默认行为。SXSSFWorkbook的临时 XML 文件会占用可观的磁盘空间——默认情况下每个 Sheet 的临时文件按行集写入磁盘数据量越大临时文件膨胀越明显。因此文档给出的核心结论是启用临时文件压缩可以用少量 CPU 开销换取磁盘占用的大幅下降。批量写入 压缩临时文件的标准写法官方文档给出的核心示例源自仓库测试LargeDataTest的实战用法如下这是大文件导出的推荐骨架Test public void largeFileWrite() { String fileName largeFile System.currentTimeMillis() .xlsx; try (ExcelWriter excelWriter FesodSheet.write(fileName, DemoData.class) .registerWriteHandler(new WorkbookWriteHandler() { Override public void afterWorkbookCreate(WorkbookWriteHandlerContext context) { Workbook workbook context.getWriteWorkbookHolder().getWorkbook(); if (workbook instanceof SXSSFWorkbook) { ((SXSSFWorkbook) workbook).setCompressTempFiles(true); } } }) .build()) { WriteSheet writeSheet FesodSheet.writerSheet(Template).build(); // Write data in batches — each data() call returns one batch for (int i 0; i 1000; i) { excelWriter.write(data(), writeSheet); } } }要点拆解FesodSheet.write(fileName, DemoData.class)入口方法见 FesodSheet.javaDemoData.class用于通过ExcelProperty注解驱动表头与字段映射。registerWriteHandler(...)在 AbstractExcelWriterParameterBuilder 中注册写处理器。WorkbookWriteHandler提供了afterWorkbookCreate钩子回调时机在工作簿创建完成之后。context.getWriteWorkbookHolder().getWorkbook()WorkbookWriteHandlerContext同时暴露writeContext与writeWorkbookHolder见 WorkbookWriteHandlerContext.java从中取到实际创建的Workbook实例。((SXSSFWorkbook) workbook).setCompressTempFiles(true)对SXSSFWorkbook开启临时文件压缩。POI 会以 GZIP 压缩中间 XML 临时文件显著降低磁盘占用代价是略微增加的 CPU 开销。try-with-resourcesexcelWriter.write(data(), writeSheet)ExcelWriter实现了AutoCloseableclose()内部调用finish()完成收尾见 ExcelWriter.java。每次write()只提交一个批次绝不要一次性传入全部数据。这段代码在仓库中有对应的真实测试LargeDataTest.write() 以 5000 批 × 每批 100 行共 50 万行、25 列的规模验证了批量写出并断言 Fesod 的耗时不超过原生 POI 直接SXSSFWorkbook写法的两倍同一测试类里的readAndWriteCsv()还覆盖了 CSV 大文件的批量写出与回读断言读到 499999 行。底层架构数据如何一路流到最终 xlsx官方文档用一张流程图示出了大文件写出的整体架构整理如下Data (in memory, batched) Fesod POI/SXSSF │ │ │ ├─ 100 rows batch ───────────▶ write() ──────▶ temp XML (compressed) ├─ 100 rows batch ───────────▶ write() ──────▶ temp XML (append) │ ... (1000 batches) │ │ └─ close() ──────────────────▶ finalize ─────▶ final .xlsx结合源码可以更精确地还原这条链路构造阶段WorkBookUtil.createWorkBook()决定SXSSFWorkbook的创建ExcelBuilderImpl在完成各 Sheet、Table 初始化后触发工作簿创建回调此时注册的WorkbookWriteHandler.afterWorkbookCreate得以执行因此可以安全地设置setCompressTempFiles(true)。写批阶段excelWriter.write(data(), writeSheet)内部通过ExcelWriteAddExecutor将当前批次的模型对象按注解元数据逐行写出。SXSSF 把超出内存窗口的行冲刷到临时 XML追加到磁盘临时文件压缩开启时该临时文件为 GZIP 流。收尾阶段close()→finish()。仓库在 WriteContextImpl 中对SXSSFWorkbook显式调用dispose()释放行窗口缓存随后把各 Sheet 的临时数据合并写出为最终.xlsx。作为收尾的一部分内置的 DimensionWorkbookWriteHandler 会在afterWorkbookDispose阶段通过反射读取SXSSFSheet._sh修正每个 Sheet 的 dimension 区域引用保证大文件打开时表格范围正确。理解这条链路的意义在于批次的每一行数据在内存中只短暂存活真正持久化的是落盘的临时 XML因此内存峰值只与「单批大小 SXSSF 窗口」相关与总行数基本无关。性能调优建议官方文档给出的四条实践建议每一条都可以落到具体参数上建议做法依据 / 备注用ExcelWriter批量写循环调用write()而非一次性doWrite()全量数据源码链路见上文测试见 LargeDataTest开启临时文件压缩setCompressTempFiles(true)磁盘受限环境的首选代价是略微提高 CPU 占用调优批次大小文档示例为每批 100 行可按行宽与可用内存调整批次越小内存峰值越低但批次数增多、整体吞吐下降监控临时目录大小FileUtils.getPoiFilesPath()见下文批次大小的选择是一个内存与吞吐的权衡行越宽字段越多、单元格内容越长单位批次的临时对象越多批次应适当调小内存充裕、追求吞吐时则可调大。可以按「预计峰值内存 ≈ 单批对象大小 SXSSF 窗口默认 100 行」的模型粗估。监控临时目录POI 的 SXSSF 临时文件默认写入系统临时目录。FesodSheet 在 FileUtils.java 中提供统一入口// 查看当前 POI 临时文件目录 String poiPath FileUtils.getPoiFilesPath(); // 也可以在写入前自定义临时目录 FileUtils.setPoiFilesPath(/data/tmp/poi);建议在生产环境将该目录指向有容量保证的独立磁盘分区并配合定时监控du -sh poiPath观察磁盘占用是否符合预期若未开启压缩时占用暴涨可优先启用setCompressTempFiles(true)。此外FileUtils还提供getTempFilePrefix()/setTempFilePrefix()、getCachePath()/setCachePath()用于定制临时文件前缀与缓存路径便于在共享主机上隔离多个实例的临时文件。配套的大文件读取方案大文件导出往往伴随着对既有大文件的分析读取。官方文档在末尾明确指出大文件读取优化的完整方案在 Large Data 一节对应的仓库文档为 website/docs/sheet/help/large-data.md与本文属于同一「大文件」主题的两半。该节的核心策略与这里形成对照读取端默认采用「先落盘再反序列化」策略共享字符串表Shared Strings小于 5MB 时驻留内存超过 5MB 的部分存入临时文件读取大文件时长期驻留内存通常在 30MB 量级。需要精细控制时可用readCacheSelector(new SimpleReadCacheSelector(5, 20))指定「文件存储阈值」与「文件存储时的内存缓存上限」两个参数内存充足且文件不大时可改用readCache(new MapCache())强制内存缓存以换取更高读取速度。读写两端合起来就构成了 FesodSheet 处理超大表格的完整闭环写入用流式 压缩临时文件读取用分级缓存策略。总结面对 10 万行以上的导出需求推荐的生产实践可以概括为三步入口FesodSheet.write(fileName, DemoData.class)创建流式写入器压缩通过WorkbookWriteHandler.afterWorkbookCreate对SXSSFWorkbook调用setCompressTempFiles(true)用少量 CPU 换磁盘空间分批try-with-resources包裹ExcelWriter按可承受的批次大小如 100 行/批循环write()最后自动close()收尾。同时把临时目录纳入监控FileUtils.getPoiFilesPath()并结合大文件读取的缓存策略即可在不改动业务模型的前提下稳定支撑百万行级别的 Excel 读写任务。赞分享后端【免费下载链接】fesodFast. Easy. Done. Processing spreadsheets without worrying about large files causing OOM.项目地址https://gitcode.com/gh_mirrors/fast/fesod点击查看免费下载相关推荐Apache Fesod 文档贡献指南基于 Docusaurus 官网的文档编写、预览与 PR 提交全流程Apache Fesod 文档贡献指南基于 Docusaurus 官网的文档编写、预览与 PR 提交全流程 本文以 Apache FesodIncubati后端GoFrame gzip流式压缩大文件传输优化GoFrame gzip流式压缩大文件传输优化 引言大文件传输的性能瓶颈 在现代Web应用中大文件传输如日志文件、备份数据、媒体资源常常面临带宽占用高Web框架后端CLIApache FesodIncubating入门实战用流式 API 高性能读写大规模 Excel 的 Java 指南Apache FesodIncubating入门实战用流式 API 高性能读写大规模 Excel 的 Java 指南 Apache FesodIncub后端上一篇Semi Design AI 技能包SKILL.md完全指南借助 MCP 工具与最佳实践让 AI 高效编写组件代码下一篇MouseTester 快速上手如何 3 步实测鼠标 CPI 与回报率曲线创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑