小文件读写应使用os.readfile和os.writefile,适用于配置文件、json/yaml解析、临时token等单次操作;大文件或需流式处理时必须用os.open+bufio.scanner或io.copy,ioutil在go 1.16+已彻底弃用。

小文件直接用 os.ReadFile 和 os.WriteFile 就够了,它们自动开/关文件、不漏资源;但大文件或需要追加、同时读写、强制落盘时,必须切到 os.OpenFile + 手动控制。
os.ReadFile 和 os.WriteFile 适合什么场景
这两个函数是 Go 1.16+ 的标准快捷路径,封装了打开、读/写、关闭全过程,省去 defer file.Close() 的心智负担。
- 适用:配置文件(
config.json)、临时 token、小日志快照、单次生成文本等,文件体积建议控制在几十 MB 以内 - 常见错误:
open /etc/myapp/config.yaml: permission denied—— 写入路径无写权限,尤其 Linux/macOS 下非用户目录需提前sudo或改路径 - 注意:
os.WriteFile总是覆盖,不能追加;传参必须是[]byte,别传string而不转:用[]byte("hello"),不是string([]byte) - 权限参数
perm只影响新建文件,已存在文件的权限不变;推荐写成0644,别写644(那是十进制)
大文件必须用 os.OpenFile + bufio.Scanner 或 io.Copy
几十 MB 以上就别用 os.ReadFile,否则容易触发 runtime: out of memory;流式处理才是正解。
-
bufio.Scanner逐行读:适合解析日志、CSV、按条件过滤行;默认单行上限 64KB,超长会报scanner: token too long,需手动扩容:scanner.Buffer(make([]byte, 4096), 1 - 读完必须检查
scanner.Err(),否则磁盘拔出、IO 中断等错误会被静默吞掉 -
io.Copy(dst, src)复制大文件:内部按 32KB 分块,内存友好;记得defer src.Close()和defer dst.Close(),否则句柄泄漏,Linux 下跑久会卡在too many open files - 别在
for scanner.Scan()循环里长期保存scanner.Text()返回值——下一次Scan()会复用底层 buffer,旧字符串内容被覆盖
os.OpenFile 的 flag 组合决定行为边界
os.OpenFile 是底层统一入口,os.Create、os.ReadFile 全是它的封装。flag 组合错了,行为就不可控。
- 合法组合示例:
os.O_RDWR | os.O_CREATE、os.O_WRONLY | os.O_APPEND - 非法组合:
os.O_RDONLY | os.O_CREATE会 panic —— 只读模式无法创建文件 -
O_APPEND和O_TRUNC互斥;O_SYNC强制每次写都落盘,性能低但防断电丢数据 - 权限参数
perm仅在O_CREATE生效,且只对新建文件起作用;父目录权限太严(如0700),子目录即使设0755也无法被组/他人访问
目录操作常踩的坑:os.ReadDir 和 os.MkdirAll
对路径做任何操作前,先确认它是目录而不是文件;建目录别指望系统自动补全父级。
-
os.ReadDir只接受目录路径,若传入文件或不存在路径,直接返回*os.PathError;务必先os.Stat(path)+info.IsDir()校验 -
os.Mkdir("a/b", 0755):只建b,要求a已存在;os.MkdirAll("a/b/c", 0755)才会递归建全路径,生产环境推荐用这个 - 权限值必须写成八进制字面量,
0755正确,755是十进制,等价于八进制01137,实际权限完全失控 -
os.RemoveAll是“尽力而为”:遇到权限拒绝、文件占用、只读文件等,不会中断,而是跳过并继续删,最后只返回第一个错误 —— 别以为返回nil就代表全删干净了
真正麻烦的从来不是 API 本身,而是路径是否存在、权限是否足够、flag 是否互斥、buffer 是否复用、错误是否被忽略——这些点不盯紧,os 包再简洁也救不了 runtime panic 或数据静默丢失。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











