Go 文件与 IO 学习笔记:从文件读写理解 Go 的 IO 设计

发布时间:2026/8/2 11:36:01
Go 文件与 IO 学习笔记:从文件读写理解 Go 的 IO 设计 刚开始学习 Go 的文件操作时最容易产生一个疑问为什么 Go 里面读取文件要用os又出现了io还有bufio刚开始看这些包的时候会感觉它们功能很重复。比如读取文件file.Read()也可以io.ReadAll(file)还可以bufio.NewReader(file)到底应该用哪个其实它们负责的事情完全不同。一、先理解 IO 是什么IO 的全称是Input / Output也就是输入和输出。简单理解程序需要和外部交换数据。例如读取文件硬盘 | | 数据 ↓ Go程序写入文件Go程序 | | 数据 ↓ 硬盘这就是 IO。二、Go 为什么设计 Reader 和 Writer假设没有接口。读取文件file.Read()读取网络conn.Receive()读取字符串string.Get()每一种数据来源都有自己的方法。那么代码会非常混乱。Go 的设计不关心数据来自哪里。只要求你能不能读取如果能实现io.Reader你能不能写入实现io.Writer于是文件os.File可以读。字符串strings.Reader也可以读。网络net.Conn也可以读。它们虽然来源不同但是使用方式一样Read()三、第一次读取文件最简单package main import ( fmt os ) func main(){ file,err:os.Open(hello.txt) if err!nil{ return } defer file.Close() buf:make([]byte,10) n,err:file.Read(buf) fmt.Println(string(buf[:n])) }这个过程打开文件 ↓ 创建存储空间 ↓ Read读取 ↓ 打印数据但是这里有一个问题如果文件10GB怎么办你不能make([]byte,10GB)全部放内存。所以出现四、流式读取Go 不喜欢“一次性拿完”。更推荐“一点一点处理”。例如for{ n,err:file.Read(buf) if n0{ 处理数据 } if errio.EOF{ break } }这就是流式 IO。类似喝水。不是一次喝完一桶。而是一口一口喝。五、bufio 为什么出现如果每次Read()都会访问磁盘。比如读取一万个字符。可能读取1个字符 访问磁盘 读取1个字符 访问磁盘 ...效率很低。所以bufio 增加缓存。变成文件 ↓ bufio缓存 ↓ 程序一次读取一批数据。六、文件复制为什么用 io.Copy以前我们可能这样for{ 读取 写入 读取 写入 }但是 Go 已经帮我们封装io.Copy(dst,src)它内部Reader ↓ 缓冲 ↓ Writer自动完成。所以文件复制io.Copy(target,source)就是最标准写法。七、filepath 解决什么问题很多初学者会这样path : data/nameLinux 可以。Windows可能出现问题。所以filepath.Join()帮你处理不同系统路径。总结学习 Go IO 最重要的不是记os.OpenFile bufio.Scanner filepath.Ext而是理解数据从哪里来 ↓ Reader ↓ 程序处理 ↓ Writer ↓ 数据到哪里去文件os.File网络net.Conn内存bytes.Buffer最后都会统一成io.Reader io.Writer