ARTICLE · 986306
Excel打不开20万行怎么办?C#流式读取实战
上个月帮朋友处理一批销售数据,文件打开那一刻 Excel 直接闪退了。
文件多大?70万行,47MB。行数超了 Excel 的上限(1,048,576行),而且字段类型混乱——日期有的是"2023-01-01",有的是"2023/1/1",有的是"2023年1月1日"。
他说"以前用 Access 能跑,后来 Access 也崩了"。
这种文件,一般程序员会说"拆成多个文件处理"。但我不想每次手动拆、每次合并——这个工作以后每个月都要跑一次。
我决定写一套数据处理框架。
第一层:流式读取
第一步是读文件。传统方式是把整个文件加载到内存再处理,70万行直接爆掉。
我用的方案是 ZipArchive + XmlReader SAX 解析——不需要把整个 Excel 加载到内存,每次只读一行,处理完就丢掉。读取70万行,内存峰值不超过 10MB。
关键代码长这样:
using var reader = new StreamingExcelReader(”sales.xlsx”);reader.Accumulate = false; // 关闭内存累积,纯流式reader.OnRow = (rowIdx, cells) =>{// 边读边处理,读完一行处理一行ProcessRow(cells);};reader.Open();
Accumulate = false 是关键。打开后内部不会维护任何行集合,每读一行触发一次 OnRow 回调,数据处理完就直接丢弃,内存始终保持恒定。
第二层:SQLite in-memory 做查询引擎
读完的数据不能一直放内存——下次查询还要用。传统方案是写回数据库文件,但频繁读写磁盘也慢。
我的方案是直接用 SQLite in-memory 模式:数据进内存后立即导入一张临时表,用 SQL 做过滤、分组、聚合。查询完了数据还在内存,下一次查询直接复用,不需要重新读文件。
await DataConverter.ImportToSqliteAsync(data, engine);var result = await DataConverter.ExportFromSqliteAsync(engine,”SELECT region, SUM(amount) FROM sales GROUP BY region”);
整个流水线:流式读取 → 内存表 → SQLite 查询 → 结果返回,不需要写磁盘,不需要维护数据库服务。
第三层:MessagePack 序列化
有时候数据需要缓存,或者跨进程传输。最直接的方案是 JSON,但 JSON 对二进制数据和中文支持都不算友好,而且体积偏大。
我用的是 MessagePack——二进制序列化格式,比 JSON 小 30-50%,序列化速度也更快。最关键的是它支持零反射的 IL 生成,不需要用 Newtonsoft.Json 那种反射方案,GC 压力小很多。
// 序列化(RsData → byte[])var bytes = RsDataSerializer.Serialize(result);// 反序列化(byte[] → RsData)var restored = RsDataSerializer.Deserialize(bytes);
完整流水线
这套组合拳打下来,处理 70万行 Excel 的完整流程:
流式读取:内存峰值 < 10MB,不崩盘 SQLite in-memory:查询直接在内存跑,不用磁盘 IO MessagePack:缓存和传输都用二进制,体积小速度快
.xlsx 文件│▼ 流式读取(内存 < 10MB)RsData 内存表│├──► SQLite in-memory 查询(直接 SQL,不需要磁盘)│ ││ ▼│ 结果 RsData│└──► MessagePack 序列化(缓存/传输用二进制)
这套架构不是专门给 Excel 用的——DBF 文件、CSV、任何结构化数据源,只要符合"大文件+需要反复查询"这个特征,都能用这套思路处理。
副业视角
说完技术说钱。
这套东西能接的活,大致两类:
一是帮小工厂/小公司处理历史数据。很多小公司有十几年积累的 Excel/CSV 数据,老板想查某个供应商5年的供货记录,业务员说"查不了"——Excel 根本打不开。这种活儿报价 2000-4000 一次,月跑一次的话月费 800-1200。
二是帮别人做数据迁移。有些公司要从旧的 Access/FoxPro 系统迁移到新的 ERP,数据格式老旧没人敢碰,用这套流式处理方案反而比大多数方案都稳。
往期相关:
《技术文档中文化渠道清单:我靠这5个地方接到单》 《技术文档中文化,这3个坑我劝你别踩》
你平时处理大文件时,有没有被 Excel 崩过?用的什么办法?评论区聊聊。
如果这篇对你有用,点个「在看」让更多同行看到 👇
关注我,每周分享程序员可落地的副业方向。