f.getrows会oom而f.rows不会,因为前者全量加载xml解析为二维字符串数组,内存随文件规模剧增;后者基于sax流式解析,每次仅驻留一行原始片段,内存稳定在几十mb级别。

为什么f.GetRows会OOM而f.Rows不会
因为f.GetRows把整张表的 XML 全部解析成[][]string,哪怕你只取第 50 万行第 3 列,它也得先把前面所有行都加载进内存。一个 15MB 的 .xlsx 解压后 XML 常超 600MB,Go 对象开销再叠加上去,2GB+ 内存很常见。f.Rows则完全不同:它基于 SAX 模式流式解析 XML,每次只 hold 一行的原始片段,内存占用稳定在几十 MB 级别。
f.Rows遍历必须检查Next()返回值
流式迭代器不保证每行都合法 —— 空行、损坏的单元格引用、非法字符都可能导致rows.Next()返回false,此时再调用rows.Row()会 panic。
- 必须写成
for rows.Next() { row, err := rows.Row() },不能省略rows.Next()判断 - 遇到
err != nil时建议log.Printf并continue,别直接return或panic - 务必加
defer rows.Close(),否则底层 goroutine 和文件句柄不会释放 - 跳过前 N 行只能靠循环调用
rows.Next(),流式 API 不支持随机寻址
只读特定列时用row.GetCell而非遍历Cells
即使你只关心 A、D、F 三列,row.Cells仍会解析整行所有单元格(含空列),浪费 CPU 和内存。row.GetCell("A")是懒加载:它从当前行 XML 片段中直接定位并提取指定列,其余列完全不解析。
Colly 是一个用于 Go 语言的快速开源爬取和爬虫框架。它适用于从简单的页面提取到异步爬虫处理大量页面集合,支持请求回调和结构化解析。
- 列名用字符串传入:
row.GetCell("A")、row.GetCell("D12")都合法 - 若列不存在或为空,
GetCell返回空字符串,不会 panic - 避免先取
row.Cells再按索引取值,那等于放弃流式优势
分块读取+随机采样20万行的实操要点
Excelize 本身不提供“跳到第 N 行”或“按偏移读块”的能力,所谓“分块”只能靠应用层控制:一边流式读,一边用 reservoir sampling 或分段缓存 + rand.Perm 实现。
- 内存敏感场景推荐 reservoir sampling:单次遍历,O(1) 额外空间,等概率抽样
- 若需精确控制每块大小(如每 10 万行一组),可用切片缓存当前块,满即处理并清空
-
rand.Seed(time.Now().UnixNano())必须在 main 开头调一次,别在循环里反复 seed - 注意:流式读仅支持
.xlsx,.xls文件必须先转格式,否则f.Rows直接报错
真正难的不是代码怎么写,而是意识到 Excelize 的流式 API 是单向、不可 rewind 的 —— 一旦rows.Next()过去,那行数据就没了。所有“随机”“分块”“跳过”逻辑,都得在这一条不可逆的流上设计清楚。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










