Go 入门(14):文件 I/O——os 与 bufio 标准库
更新时间:2026-09-01。本文是
languages/go/beginner/入门层第 14 篇,接 JSON 序列化。文件 I/O 是每门语言的基础操作,Go 用os包打开文件,bufio提供缓冲读写,io包提供通用接口。
本文要回答的问题
- 怎么打开和关闭文件?defer 关文件的惯例是什么?
- 怎么按行读取文件?bufio.Scanner 怎么用?
- 怎么写入文件?os.Create 和 os.OpenFile 的区别?
- 错误处理在文件操作里怎么安排?文件不存在怎么判断?
一、打开文件:os.Open
go
f, err := os.Open("data.txt")
if err != nil {
log.Fatal(err) // 文件不存在,权限错误等
}
defer f.Close() // 函数返回前关闭文件核心模式:打开 → 检查错误 → defer 关闭 → 读写操作。
defer f.Close() 是 Go 的惯例写法,不管你函数里有几个 return 或是 panic,Close 都会在函数返回时执行。
二、按行读取:bufio.Scanner
go
f, err := os.Open("data.txt")
if err != nil {
log.Fatal(err)
}
defer f.Close()
scanner := bufio.NewScanner(f)
for scanner.Scan() {
line := scanner.Text() // 当前行,不带换行符
fmt.Println(line)
}
if err := scanner.Err(); err != nil {
log.Fatal(err) // 读取过程中出错
}bufio.Scanner 默认按行分割,也可以自定义分割函数。
三、一次性读取整个文件:os.ReadFile
go
data, err := os.ReadFile("data.txt")
if err != nil {
log.Fatal(err)
}
fmt.Println(string(data))os.ReadFile 直接读取整个文件到内存,适合小文件。大文件用 bufio.Scanner 逐行读。
四、写入文件
创建新文件或覆盖写:os.Create
go
f, err := os.Create("output.txt")
if err != nil {
log.Fatal(err)
}
defer f.Close()
_, err = f.WriteString("Hello, World!\n")
if err != nil {
log.Fatal(err)
}追加写:os.OpenFile
go
f, err := os.OpenFile("output.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Fatal(err)
}
defer f.Close()
_, err = f.WriteString("append line\n")第二个参数是打开标志:
os.O_RDONLY:只读os.O_WRONLY:只写os.O_RDWR:读写os.O_CREATE:不存在就创建os.O_APPEND:追加写os.O_TRUNC:清空再写
一次性写入:os.WriteFile
go
data := []byte("Hello, World!\n")
err := os.WriteFile("output.txt", data, 0644)五、文件是否存在:os.Stat
go
_, err := os.Stat("data.txt")
if os.IsNotExist(err) {
fmt.Println("文件不存在")
} else if err != nil {
// 其他错误(权限等)
log.Fatal(err)
}六、io.Reader 和 io.Writer 接口
Go 的 I/O 核心是两个接口:
go
type Reader interface {
Read(p []byte) (n int, err error)
}
type Writer interface {
Write(p []byte) (n int, err error)
}文件、网络连接、缓冲区都实现了这些接口,所以可以统一处理:
go
// 拷贝文件内容到标准输出
f, _ := os.Open("data.txt")
defer f.Close()
io.Copy(os.Stdout, f) // 从 f 读,写到 stdout七、常见坑对照
| 坑 | 现象 | 对策 |
|---|---|---|
| 忘记 defer Close | 文件句柄泄漏,程序跑久了打不开文件 | 打开后立即 defer f.Close() |
| 不检查错误 | 文件不存在直接 panic | 每次文件操作都检查 err |
| bufio.Scanner 不检查 Err | 读到一半断网了不知道 | 循环后检查 scanner.Err() |
| 大文件用 ReadFile | 内存撑爆 | 用 bufio.Scanner 逐行读 |
| 写入不 Flush | bufio.Writer 缓冲未刷新 | 用 defer w.Flush() 或 w.Flush() |
相关与延伸
下一篇:命令行参数——flag 包;io.Reader/Writer 接口是 Go 组合设计的核心,多处复用;文件 I/O 的缓冲和系统调用,进阶层讲;os.File 和 bufio 的底层实现,对应 C 的 fopen/fclose 和 fgetc/fgets。
一句话总结
Go 文件 I/O:os.Open 打开,defer f.Close() 关闭,这是标准模式;bufio.Scanner 按行读大文件,os.ReadFile 一次性读小文件;os.Create 创建写,os.OpenFile 追加写或自定义模式;io.Reader/io.Writer 接口统一了所有 I/O 操作。