Go 读文件换行符不一致因 bufio.Scanner 默认按\n切分,而Windows用\r\n、Linux/macOS用\n;跨平台应统一用strings.TrimRight(line, "\r\n")清理行尾换行符,写文件需按目标平台显式指定\r\n或\n。

Go 读文件时换行符为什么在 Windows 和 Linux 上表现不一致
因为 Go 的 bufio.Scanner 默认按 \n 切分,而 Windows 文件用 \r\n、Linux/macOS 用 \n。当在 Linux 上读 Windows 生成的文件,\r 会残留在行末(比如 "hello\r");反之在 Windows 读 Linux 文件虽能切分,但跨平台逻辑可能因隐含 \r 出错。
- 不要依赖操作系统默认文本模式(Go 没有类似 Python 的
"t"模式) -
os.Open总是二进制打开,换行符处理完全由上层逻辑决定 - 如果用
io.ReadAll+strings.Split,同样要手动清理\r
用 strings.TrimRight 处理跨平台换行符最简单可靠
无论文件来自哪,统一用 strings.TrimRight(line, "\r\n") 去掉行尾所有 \r 和 \n ——它能安全处理 \n、\r\n、甚至老 Mac 的 \r(已少见),且不会误删行内字符。
- 别用
strings.TrimSpace:它会删空格和 tab,破坏缩进或数据格式 - 别用
strings.TrimSuffix(line, "\r\n"):只匹配后缀,对纯\n或\r无效 - 示例:
line := strings.TrimRight(line, "\r\n")放在scanner.Scan()循环体内即可
需要保留原始换行符时,改用 bufio.NewReader + ReadString
当业务必须区分 \n 和 \r\n(如协议解析、文件重写),就不能用 Scanner,得用 bufio.NewReader 手动读到换行符为止,并检查结尾。
-
reader.ReadString('\n')返回包含\n的字符串,再判断末尾是否为\r\n - 若返回字符串以
\r\n结尾,说明源文件是 Windows 风格;若仅为\n,则是 Unix 风格 - 注意:
ReadString可能返回io.EOF,最后一行无换行符时需单独处理
写文件时显式指定换行符,避免依赖 runtime.GOOS
别写 if runtime.GOOS == "windows" { fmt.Fprintln(w, line) } ——这会让输出依赖执行环境,而非目标平台。真正要兼容,就按目标平台语义写:
立即学习“go语言免费学习笔记(深入)”;
- 写配置文件给 Windows 程序用?一律用
\r\n:w.Write([]byte(line + "\r\n")) - 写日志给 Linux 容器消费?固定用
\n - 通用文本导出?优先选
\n(POSIX 标准),除非明确要求 CRLF
换行符不是“适配系统”,而是“适配下游消费者”。很多 bug 出在开发者以为写了 Fprintln 就自动适配,其实只是用了当前系统的 fmt 默认行为。


















