Go语言读取文件的5种常用方法,从简单到进阶

Go程序时,经常要处理配置文件、日志、用户数据这些文本内容。比如你做个小工具,想把 config.json 里的端口号读出来;或者写个日志分析脚本,需要逐行扫一遍 access.log —— 这些都绕不开「读文件」这一步。

1. 最简单的:ioutil.ReadFile(已弃用但很多人还在用)

Go 1.16 之前,很多人第一反应就是 ioutil.ReadFile。它一行搞定,适合小文件:

data, err := ioutil.ReadFile("settings.txt")
if err != nil {
    log.Fatal(err)
}
fmt.Println(string(data))

注意:这个函数在 Go 1.16+ 已被移到 os.ReadFile,老项目可能还见得到,新代码建议直接用下面这个。

2. 推荐新手入门:os.ReadFile

这是目前最简洁安全的方式,自动处理打开、读取、关闭全流程:

data, err := os.ReadFile("user.json")
if err != nil {
    log.Printf("读取失败:%v", err)
    return
}
var user map[string]interface{}
json.Unmarshal(data, &user)

适合读取几百KB以内的配置、JSON、YAML 等小文件,不占心力。

3. 按行读:bufio.Scanner(适合日志、列表类文本)

要是文件很大,比如一个 200MB 的 access.log,全读进内存就太莽了。这时候用 bufio.Scanner 一行一行来:

file, _ := os.Open("access.log")
defer file.Close()

scanner := bufio.NewScanner(file)
for scanner.Scan() {
    line := scanner.Text()
    if strings.Contains(line, "404") {
        fmt.Println("发现404错误:", line)
    }
}

它默认单行上限 64KB,够日常用;真有超长行,可以调 scanner.Buffer(make([]byte, 64), 1<<20) 扩容。

4. 流式读取:io.ReadFull 和 io.Copy(大文件搬运)

想把一个 ISO 镜像复制到 U 盘?或做文件校验?别 load 全部进内存,用 io.Copy 直接管道传输:

src, _ := os.Open("linux.iso")
dst, _ := os.Create("/mnt/usb/linux.iso")
defer src.Close()
defer dst.Close()

_, err := io.Copy(dst, src) // 边读边写,内存只占几KB

如果要精确读固定长度(比如解析二进制头),用 io.ReadFull 更稳妥。

5. 精确控制:os.Open + Read + Close(适合自定义逻辑)

有些场景得自己拿捏节奏,比如边读边解密、跳过BOM头、按块校验MD5……这时手动打开+读取更灵活:

file, err := os.Open("secret.enc")
if err != nil {
    panic(err)
}
defer file.Close()

buf := make([]byte, 4096)
for {
    n, err := file.Read(buf)
    if n > 0 {
        // 对 buf[:n] 做解密或处理
        processChunk(buf[:n])
    }
    if err == io.EOF {
        break
    }
    if err != nil {
        log.Fatal(err)
    }
}

注意:Read 不保证一次读完全部内容,必须循环处理 n 字节数,这是新手常踩的坑。

小提醒

路径别写死,多用 filepath.Join("config", "db.yaml") 拼接;中文路径在 Windows 上记得用 UTF-8 编码(一般默认没问题);读取前先 os.Stat 判断文件是否存在,比靠 err 判断更直观。