用 os.readfile 最快读小文件:它内部一次性分配足够内存并调用 syscall.read,避免多次系统调用和内存拷贝,适合已知较小且可容纳于内存的文件。

用 os.ReadFile 最快读小文件(
多数时候你不需要自己开 os.File、写循环、拼切片——os.ReadFile 就是干这个的,底层已优化为一次性分配足够内存并调用 read 系统调用。
常见错误是看到文档里有 io.ReadFull 或 bufio.Scanner 就以为“更标准”,结果小文件反而多绕两道指针跳转,还容易漏关文件或忽略 EOF 判断。
-
os.ReadFile返回[]byte,不是string;需要字符串时显式转:string(data) - 路径必须是完整路径或相对当前工作目录(
go run启动位置),不支持类似 Node.js 的__dirname - 如果文件不存在,错误是
*os.PathError,检查可用errors.Is(err, os.ErrNotExist)
读大文件别全载入内存,用 bufio.Scanner 行读取
读几百 MB 日志或 CSV 时,os.ReadFile 会直接 OOM。这时候得流式处理,bufio.Scanner 是最省心的选择——它默认每行最多 64KB,超长会报 scanner.ErrTooLong,但你可以调 ScanLines 或自定义分隔符。
注意它不是为二进制设计的,遇到 \x00 或非 UTF-8 字节不会报错,只是截断;真要读二进制流,换 bufio.Reader + Read。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 默认缓冲区 4KB,可通过
scanner.Buffer(make([]byte, 64*1024), 1 调大最大 token 长度 - 不要在循环里重复
os.Open;一个*os.File可复用多次 -
scanner.Text()返回的是内部缓冲区的引用,循环中需立即拷贝:line := scanner.Text(); process(line),否则下一次Scan()会覆盖
ioutil.ReadFile 已弃用,别再用
Go 1.16 起 ioutil 包整体移到 io 和 os 下,ioutil.ReadFile 只是 os.ReadFile 的别名,但保留它会让新人误以为它是“独立工具包”,实际编译会警告:"ioutil" is deprecated: As of Go 1.16, the same functionality is provided by package io or package os。
迁移很简单:全局替换 ioutil.ReadFile → os.ReadFile,删掉 import "io/ioutil",加 import "os"。
- 旧代码里混用
ioutil.TempDir和os.MkdirTemp容易出竞态,统一用os.MkdirTemp - 如果项目还在用 Go ioutil 调用是否都可映射到新包
按字符/UTF-8 读?别用 bufio.Scanner,改用 utf8string 或手动解码
bufio.Scanner 按字节切分,Text() 返回的仍是字节序列;如果你要逐 rune(比如统计中文字符数、跳过 emoji),它不能保证不把一个 UTF-8 多字节字符劈开。
简单场景用 strings.NewReader + utf8.DecodeRuneInString 更可控;复杂文本处理建议上 golang.org/x/text/unicode/norm,避免自己手写状态机。
-
for _, r := range string(data) { ... }本质是解码成 rune 数组,对大文件会一次性分配内存,慎用 - 逐 rune 流式读,推荐:
reader := strings.NewReader(string(data)); for reader.Len() > 0 { r, _ := utf8.DecodeRune(reader.Bytes()) } - 注意:
utf8.DecodeRune第二个返回值是 rune 字节数,不是“是否成功”;失败时返回utf8.RuneError和长度 1
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










