最常用方式是用os.ReadFile读取整个文件为[]byte再转string,然后strings.Split按换行切分;大文件必须用bufio.Scanner流式读取,避免OOM。

用 os.ReadFile 一次性读取文件到字符串再切分
Go 中最常用、最直接的方式是先用 os.ReadFile 把整个文件读成 []byte,再转为 string,最后用 strings.Split 按换行符切分。它适合中小文件(
注意:默认按 "\n" 切分,但 Windows 文件可能含 "\r\n",直接切会残留 \r。建议先用 strings.TrimSpace 或统一用 strings.Split(strings.ReplaceAll(s, "\r\n", "\n"), "\n") 处理。
示例:
data, err := os.ReadFile("config.txt")
if err != nil {
log.Fatal(err)
}
lines := strings.Split(strings.TrimSpace(string(data)), "\n")
- 若文件末尾有空行,
strings.Split会产生末尾空字符串,可加if len(lines) > 0 && lines[len(lines)-1] == "" { lines = lines[:len(lines)-1] }过滤 -
os.ReadFile内部已做缓冲优化,比手动开os.Open+bufio.Reader更轻量,别过早“优化” - 不要用
strings.FieldsFunc替代 —— 它按任意空白字符切,会破坏含空格的行内容
大文件必须用 bufio.Scanner 流式读取
文件超过几十 MB,或内存受限(如嵌入式、Serverless 环境)时,os.ReadFile 会触发 OOM。此时必须逐行读,避免把全部内容载入内存。
立即学习“go语言免费学习笔记(深入)”;
bufio.Scanner 是标准库推荐方案,它默认单行上限 64KB,超出会报 scanner.ErrTooLong。这点常被忽略,导致线上静默失败。
- 用
scanner.Buffer(make([]byte, 64*1024), 1 手动扩大缓冲区(第二个参数是最大 token 长度,例如设为 1MB) - 别用
scanner.Text()后再strings.TrimRight(..., "\r")—— 应该在循环外统一处理换行符,或改用scanner.Bytes()自己解码 - 如果某行确实超长且不可控,考虑用
bufio.NewReader+ReadString('\n'),它不限长度但需手动处理\r\n和 EOF 边界
ioutil.ReadAll 已弃用,别再用
ioutil.ReadAll 在 Go 1.16+ 已被标记为 deprecated,对应功能已移到 io.ReadAll(Go 1.16+)和保留的 os.ReadFile(更语义化)。继续用 ioutil 会导致 go.mod 版本混乱、静态检查报错,CI 可能直接失败。
迁移很简单:
// ❌ 旧写法(不推荐)
data, _ := ioutil.ReadFile("x.txt")
// ✅ 新写法(Go ≥ 1.16)
data, _ := os.ReadFile("x.txt")
// 或(需要复用 reader 时)
f, _ := os.Open("x.txt")
data, _ := io.ReadAll(f)
f.Close()
-
os.ReadFile是封装好的快捷函数,内部就是os.Open+io.ReadAll+Close,无需自己管理资源 - 如果真要复用
io.Reader(比如从 HTTP 响应体读),才用io.ReadAll;否则一律优先选os.ReadFile
按字段/结构解析比单纯切行更可靠
很多场景所谓“转成字符串数组”,其实真正需求是解析配置、日志或 CSV 行。硬切 \n 得到的 []string 往往只是中间步骤,后续还要 strings.Fields、strconv.Atoi、JSON 解析等 —— 这些都容易因格式异常 panic。
建议尽早切换到结构化解析:
- INI/TOML/YAML 配置 → 用
gopkg.in/ini.v1、github.com/BurntSushi/toml、gopkg.in/yaml.v3 - CSV → 用标准库
encoding/csv,自动处理引号、换行、逗号转义 - 固定列文本(如日志)→ 用正则或
fmt.Sscanf,比手撕strings.Split更健壮
强行把所有文件都当成纯文本切行,后期维护成本远高于初期多写几行解析逻辑。


















