open() 读写文本文件时必须显式指定 newline="",否则跨平台换行符自动转换会导致 csv/json 等模块出错;pathlib.Path.read_text() 和 write_text() 默认等效于 newline="",更安全。

open() 读写时必须显式传 newline=""
Python 3 的 open() 在文本模式下默认会做换行符标准化:读取时把 \r\n、\r 都转成 \n,写入时又按平台自动补回 \r\n(Windows)或 \n(Linux)。这看似省心,实则埋雷——尤其当你用 csv、json 等模块处理文件时,它们内部依赖 newline="" 才能避免重复转换。
正确做法是:只要操作纯文本且需跨平台一致行为,一律加 newline="":
- 读文件:
open("data.csv", "r", newline="") - 写文件:
open("out.json", "w", newline="") - 配合
csv.writer或json.dump时,这个参数不是可选,是必须
用 pathlib.Path + read_text()/write_text() 更安全
pathlib.Path 的 read_text() 和 write_text() 方法默认使用 newline="" 行为,且自动处理编码。比裸写 open() 少犯错:
-
Path("config.txt").read_text(encoding="utf-8")→ 读出的每行末尾都是\n,不因平台而异 -
Path("log.txt").write_text("msg\n", encoding="utf-8")→ 写入严格为 LF,不会在 Windows 上偷偷变 CRLF - 注意:不能用
write_text()追加内容,它总是覆盖;追加请回退到open(..., "a", newline="")
别信 str.replace("\r\n", "\n") 能解决所有问题
直接字符串替换看着简单,但容易漏掉边缘情况:
- Mac Classic 的
\r换行符(虽已少见,但老文件里存在)会被忽略 - 文件末尾可能有孤立
\r(比如被截断的传输),replace()不处理 - 如果文件是二进制打开再 decode,
\r\n可能被拆成两个字节,在 UTF-16 等编码下根本匹配不到字符串"\r\n" - 真正健壮的做法是用
universal newlines模式(即默认文本模式)+newline="",让 Python 底层统一归一化
Git 配置比代码补救更前置有效
很多换行符问题其实不该在 Python 里兜底,而应在版本控制层拦截:
- 团队开发务必设
git config --global core.autocrlf input(Linux/macOS)或true(Windows),让 Git 提交时统一转 LF - 单个仓库可加
.gitattributes文件,明确声明:* text=auto eol=lf,比靠 Python 脚本事后清洗靠谱得多 - 一旦发现
bash: ./script.sh: /bin/bash^M: bad interpreter,说明 Git 没配好,优先查这里,而不是改 Python
最易被忽略的一点:newline="" 不是“可加可不加”的优化项,它是跨平台文本 I/O 的契约。缺了它,csv.writer 可能在 Windows 上多写一个 \r,json.load 在 Linux 下读 Windows 生成的文件可能因末尾 \r 报 JSONDecodeError——这些都不是 Python 版本差异,而是你没守住这个边界。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











