ARTICLE DETAIL

资讯详情

深耕网站SEO优化与搜索引擎排名提升的一线实战洞察。

告别 OutOfMemoryError:用 Apache Fesod 轻松搞定百万行 Excel 大数据处理

告别 OutOfMemoryError:用 Apache Fesod 轻松搞定百万行 Excel 大数据处理 告别 OutOfMemoryError用 Apache Fesod 轻松搞定百万行 Excel 大数据处理【免费下载链接】fesodFast. Easy. Done. Processing spreadsheets without worrying about large files causing OOM.项目地址: https://gitcode.com/gh_mirrors/fast/fesod凌晨两点监控群突然炸了。运营同事在后台点击导出本月订单报表三分钟后整个服务进程直接挂掉一堆 500 报错刷满了告警面板。打开日志一看红字刺眼java.lang.OutOfMemoryError: Java heap space。这不是段子是无数 Java 后端开发都踩过的坑——数据量一上来Excel 就成了压垮内存的那根稻草。传统工具处理几万行没问题可一旦到几十万、上百万行加载整个工作簿到堆内存的做法几乎必然触发 OOM。今天这篇文章要聊的 Apache Fesod就是专门为破解这个困局而生的一个把大数据量读写 Excel 不再担心 OOM作为核心目标的 Apache 孵化项目它走流式解析路线让百万行文件也能轻松跑通。一句话说清 Apache Fesod 是干什么的你可以把 Apache Fesod 想象成一条自动化流水线传统工具读 Excel相当于把整座仓库的货一次性搬进屋里再慢慢分拣货一多屋子堆内存必然爆掉。Apache Fesod 则不同它把货物放到传送带上一件一件流过来工人监听器拿到一件处理一件处理完就放走仓库里永远只堆着当前正在处理的少量货物。读取时文件被当作一个数据流逐行解析、逐行回调内存里最多保留当前这一批。写入时数据分批落盘边写边清不会把全部行都攒在内存里再一次性输出。所以无论文件是 10 万行还是 100 万行程序的内存占用都基本保持恒定只跟每批处理多少行有关跟文件总大小无关。这正是它能对抗 OOM 的底气所在。三分钟快速上手引入依赖就能读写 Excel上手成本极低。第一步在pom.xml里引入核心模块dependency groupIdorg.apache.fesod/groupId artifactIdfesod-sheet/artifactId version2.0.1-incubating/version /dependency如果你用 Gradle对应写法是implementation org.apache.fesod:fesod-sheet:2.0.1-incubating。第二步定义一个普通的 POJO用注解标明每一列对应哪个字段public class OrderRecord { ExcelProperty(订单号) private String orderNo; ExcelProperty(金额) private Double amount; // 省略 getter / setter }第三步读取一个 Excel 文件核心代码其实就一行FesodSheet.read(orders.xlsx, OrderRecord.class, new OrderListener()) .sheet() .doRead();写入同样简洁把数据列表直接交给 API 即可FesodSheet.write(result.xlsx, OrderRecord.class) .sheet(订单汇总) .doWrite(orderList);到这里一个能跑通的最小读写闭环就完成了。想对照更多写法可以直接看项目里的示例工程fesod-examples/fesod-sheet-examples/src/main/java/org/apache/fesod/sheet/examples/里面有从基础读写到复杂场景的各种样例。核心机制通俗拆解为什么内存占用能恒定很多人会好奇同样是读一个大文件凭什么 Apache Fesod 不爆内存秘密藏在两点第一SAX 式逐行解析而不是 DOM 式整体载入。.xlsx本质是一个 zip 压缩包里面是若干 XML。Apache Fesod 用 SAX 解析器按节点顺序扫描这些 XML读到一个row就立刻转成对象回调出去绝不把整份 XML 文档建造成内存里的树形结构。这也意味着它的内存开销与文件大小解耦——文件再大也只是多花点时间而不是多占内存。第二监听器 批处理缓冲。你传入的ReadListener决定了拿到一行后做什么。典型做法是攒够一批比如 500 条就落库、清空、继续攒下一批public class OrderListener implements ReadListenerOrderRecord { private static final int BATCH_SIZE 500; private final ListOrderRecord buffer new ArrayList(BATCH_SIZE); Override public void invoke(OrderRecord row, AnalysisContext context) { buffer.add(row); if (buffer.size() BATCH_SIZE) { saveBatch(buffer); // 批量入库 buffer.clear(); // 立刻释放 } } Override public void doAfterAllAnalysed(AnalysisContext context) { saveBatch(buffer); // 收尾处理最后不足一批的数据 } }这样一整份文件读下来堆里同时存在的对象最多就是那 500 条。想深入理解这块可以翻一翻核心源码目录fesod-sheet/src/main/java/org/apache/fesod/sheet/analysis/解析引擎、事件分发都在这里。真实场景实战百万行报表导出 批量导入场景一导出百万行报表导出和读取原理对称不要一次性doWrite(百万条),而是用ExcelWriter分片写入。下面的代码同时打开临时文件压缩进一步压榨磁盘与内存占用try (ExcelWriter writer FesodSheet.write(big_export.xlsx, OrderRecord.class) .registerWriteHandler(new WorkbookWriteHandler() { Override public void afterWorkbookCreate(WorkbookWriteHandlerContext ctx) { Workbook wb ctx.getWriteWorkbookHolder().getWorkbook(); if (wb instanceof SXSSFWorkbook) { ((SXSSFWorkbook) wb).setCompressTempFiles(true); } } }) .build()) { WriteSheet sheet FesodSheet.writerSheet(数据).build(); for (int i 0; i 10000; i) { // 分 10000 批 writer.write(queryPage(i, 100), sheet); // 每批 100 条边查边写 } }分页查询、分批写入、用完即弃整条链路对内存极其友好。写入大文件的完整示例在fesod-examples/fesod-sheet-examples/src/main/java/org/apache/fesod/sheet/examples/advanced/LargeFileWriteExample.java。场景二批量导入几十万条数据导入场景就是把前面的OrderListener接上真实的 DAO每攒够 500 条调一次批量插入最后在doAfterAllAnalysed里处理剩余数据。注意每次读取都要 new 一个监听器实例千万别复用同一个带状态的对象否则不同文件的数据会串在一起。场景三多 sheet、指定列等灵活读取FesodSheet.readSheet()支持按 sheet 序号、sheet 名称读取也支持只读指定列比如readSheet(0, 明细, Arrays.asList(0, 2))只取 A、C 两列面对结构复杂的模板文件时可以按需裁剪既省内存又省时间。详见fesod-examples/fesod-sheet-examples/src/main/java/org/apache/fesod/sheet/examples/read/下的示例。性能对比与 3 条立即可用的调优建议下表是社区在同等硬件下用 100 万行数据做的粗略对比数字因机器与数据格式而异但量级差距很有参考价值数据规模传统全量加载方案Apache Fesod效果1 万行内存占用约 150MB约 25MB节省八成以上10 万行内存占用约 1.2GB约 180MB节省八成以上100 万行频繁 OOM、无法跑完稳定完成从跑不动到跑得完再给 3 条现在就能落地的调优技巧批大小按可用堆内存动态调。内存宽裕可以调大到 1000 条/批减少落库次数内存紧张就调到 200 条优先保稳定。写大文件务必开临时文件压缩。SXSSFWorkbook.setCompressTempFiles(true)一行代码能让临时 XML 文件体积大幅缩水对应磁盘 IO 和 GC 压力都显著下降。只读需要的列、只写需要的字段。用readSheet指定列、用ExcelIgnore排除无关字段从源头减少对象构建成本。常见坑与避坑指南FAQQ1监听器里为什么数据会串多半是因为把监听器做成了 Spring 单例 Bean。它内部持有可变状态的缓冲列表多文件并发读取时必然互相污染。正确姿势是每次读取new一个实例需要 Spring 管理的 DAO 就通过构造参数传进去。Q2读 CSV 文件和读 Excel 写法一样吗一样。Apache Fesod 对 CSV 走的是同一套监听器模型CsvReaderBuilder还支持自定义分隔符与字符集。碰到带 BOM 头的 CSV 也不用手动处理直接交给库即可。Q3中途想停掉解析怎么办抛出一个ExcelAnalysisStopException解析会立即优雅终止剩下的行不会再回调已处理的数据不受影响。Q4临时文件越积越多磁盘快满了SXSSF 写大文件时会在临时目录生成中间文件。排查思路确认临时目录指向可配置、确认用 try-with-resources 正确关闭 writer、写完后按需清理该目录下的旧文件。Q5想自定义某列的格式转换怎么做实现ConverterT接口重写convertToJavaData读方向和convertToExcelData写方向两个方法再通过ExcelProperty上的converter属性挂到字段上。转换器体系在fesod-sheet/src/main/java/org/apache/fesod/sheet/converters/下内置了日期、数字、布尔、图片等几十种现成转换器。写在最后回头再看开头那个凌晨的崩溃现场问题不在数据量而在工具选型。Apache Fesod 用流水线式的流式处理把内存与文件大小解耦这件事落到了实处——读取时逐行回调、写入时分批落盘、转换器高度可扩展让你在处理百万行 Excel 大数据时也能从容不迫。 内存占用恒定百万行也不怕 OOM⚡ 流式读写性能表现稳定 注解驱动几行代码上手 Apache 孵化项目文档与示例齐全想亲手验证它的威力克隆项目跑一遍示例即可git clone https://gitcode.com/gh_mirrors/fast/fesod cd fesod mvn clean install官方文档与源码都在仓库里快速入门看website/docs/quickstart/guide.md大文件进阶看website/docs/sheet/advanced/large-file.md核心实现就在fesod-sheet/src/main/java/org/apache/fesod/sheet/。觉得有用就顺手点个 Star遇到问题也欢迎到社区提 issue、一起改进。下次再遇到导出百万行的需求你已经有答案了。【免费下载链接】fesodFast. Easy. Done. Processing spreadsheets without worrying about large files causing OOM.项目地址: https://gitcode.com/gh_mirrors/fast/fesod创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表