小文件直接用os.readfile,大文件必须流式处理;os.readfile适合几kb到几mb的配置、json等,go 1.16+已弃用ioutil.readfile;bufio.scanner默认64kb缓冲,超长行需扩容;bufio.reader更灵活,适合二进制或自定义读取;gb级文件应分块读或mmap。

小文件直接用 os.ReadFile,别绕弯;大文件必须流式处理,否则内存爆掉是分分钟的事。
什么时候该用 os.ReadFile
它适合读取几 KB 到几 MB 的配置、JSON、YAML 或模板文件。底层一次性分配内存 + 单次 read 系统调用,比手动开 *os.File + 循环拼切片还快。
- Go 1.16+ 必须用
os.ReadFile,ioutil.ReadFile已弃用,编译会警告 - 返回的是
[]byte,要字符串就显式转:string(data) - 路径是相对当前工作目录(
go run启动位置),不支持__dirname那套 - 别在 for 循环里反复调它——比如每秒读一次日志,会触发大量系统调用和内存分配
bufio.Scanner 按行读大文本文件的坑
它是日志、CSV、纯文本流的默认首选,API 简洁,但默认缓冲区只有 64KB,超长行直接报 scanner.ErrTooLong。
在 Golang 中使用 samber/hot 进行内存缓存,支持 LRU、LFU、TinyLFU、W‑TinyLFU、S3FIFO、ARC、TwoQueue、SIEVE、FIFO 等淘汰算法,提供 TTL、缓存加载器及分片功能。
- 必须在
Scan()后立刻检查s.Err(),否则最后一条错误会被静默吞掉 - 用
s.Bytes()拿原始字节,避免s.Text()多一次拷贝;若需字符串,立即拷贝:line := string(s.Bytes()) - 扩容缓冲区:调
s.Buffer(make([]byte, 4096), 1 把上限设到 1MB(注意第二个参数是最大 token 长度) - 它不是为二进制设计的——遇到
\x00或非法 UTF-8 字节不会报错,只是截断;真要读二进制,换bufio.Reader
bufio.Reader 控制读取节奏的关键点
当你需要跳过前 N 字节、读固定长度块、或处理含 \r\n/\n 混用的脏数据时,Scanner 不够灵活,得上 Reader。
- 推荐缓冲区大小:4KB–64KB,视文件大小和内存限制而定,
bufio.NewReaderSize(file, 4096) -
ReadString('\n')会把换行符一起返回;ReadLine()不带换行符,但可能返回部分行(遇到缓冲区满时) - 二进制头解析(如 PNG、MP3)优先用
io.ReadFull(file, headerBuf),它明确区分io.ErrUnexpectedEOF和其他 I/O 错误 - 读完记得
file.Seek(0, io.SeekStart)回到开头,否则后续读取从当前位置继续
GB 级文件的底线操作:分块读 + mmap
超过 10MB 就不该考虑全载入内存;真正的大文件(几十 GB)还得靠分块或 mmap。
- 固定缓冲区循环读:
buf := make([]byte, 32*1024),然后for { n, err := file.Read(buf) },每次只处理buf[:n] - mmap 适用于只读、随机访问密集的场景(如索引文件),用
github.com/edsrzf/mmap-go,映射后像操作普通 slice 一样访问,但跨平台兼容性差(Windows 支持弱) - Linux 下可加
syscall.O_DIRECT标志绕过页缓存,避免污染内存,但仅限对齐读写,且不保证所有内核版本都支持
最易被忽略的是:不同读法对错误语义的处理差异极大——os.ReadFile 要检查 errors.Is(err, os.ErrNotExist),Scanner 要在循环后查 Err(),io.ReadFull 要区分 io.ErrUnexpectedEOF 和真实错误。混用或漏判,轻则逻辑错乱,重则数据静默丢失。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










