Python csv 文件为什么要用 newline 空字符串打开
Python 使用 csv 模块读写文本文件时,通常应给 open() 传入 newline=""。它让文本层保留换行字符,由 csv 模块处理记录边界与引号内换行,避免两层转换相互干扰。这个参数并不是“删除换行”,也不表示每条记录之间没有分隔。
我更愿意把它当作一个明确的职责约定:编码交给文本流,CSV 结构交给 reader 或 writer。这样讨论空行、多行备注和跨平台导出时,就不必把所有现象都归因于文件编码。
官方文档:https://docs.python.org/3/library/csv.html
先分清文本流与 CSV 的职责
文件中的字节、文本流返回的字符串、CSV 解析后的字段,是不同层面的对象。文本流既负责字符编解码,也可以转换换行;CSV 解析器则负责分隔符、引号和记录边界。多行字段允许一条逻辑记录占用多个物理行,因此不能把每个换行都理解成下一条记录。
| 设置位置 | 控制的事情 | 常见误解 |
|---|---|---|
| open 的 encoding | 字节与字符的转换 | 指定 UTF-8 就能解决所有空行 |
| open 的 newline | 文本层如何识别或转换换行 | 空字符串会把换行清除 |
| writer 的 lineterminator | 写出记录的结束字符 | 与 open 的 newline 完全相同 |
| CSV 的引号规则 | 区分字段内容和结构字符 | 直接按行切分也能完整解析 |

读取时保留字段里的原始换行
默认的 newline=None 会在读取时把 CR、LF、CRLF 行结束形式归一成 LF。指定空字符串仍支持通用换行识别,但向上层返回未转换的行结束字符。对 CSV 来说,这可以避免在 reader 识别字段之前,文本层就改变引号内原有的换行内容。
假设“备注”字段包含 CRLF,使用默认文本读取后,CSV 可能仍能解析成一条记录,但字段里的 CRLF 已变成 LF。因此,“没有报错”和“字段内容保真”是两个判断标准。我的选择是直接使用文档建议的空字符串设置,而不依赖数据刚好没有多行字段。
import csv
# 交给 csv.reader 解释引号中的换行;文本层不预先替换
with open("feedback.csv", "r", encoding="utf-8", newline="") as source:
reader = csv.DictReader(source)
for row in reader:
note = row["备注"]
# repr 让回车、换行可见,不靠屏幕换行判断字段内容
print(row["编号"], repr(note))
这个例子约定输入有“编号”和“备注”表头,遇到缺列还需要应用自己的业务处理。这里用 repr 帮助读者观察控制字符;本文没有执行示例,也不声称展示了本地输出。若数据量很大,逐条处理 reader 返回的记录即可,不必为了读取 CSV 先把整个文件装进列表。
写入时避免换行被重复转换
csv 的默认 excel 方言通常用 CRLF 结束一条记录。若文本层又把其中的 LF 转成平台默认 CRLF,就可能形成 CRCRLF。某些读取程序把多出来的回车解释成额外行边界,表现为每条记录之间多空行;具体显示方式仍取决于读取工具。
import csv
records = [
{"编号": "F-204", "备注": "需要复核\r\n已联系负责人"},
{"编号": "F-205", "备注": "已确认"},
]
# 文本层不转换换行;writer 负责分隔、引号和记录结束符
with open("feedback.csv", "w", encoding="utf-8", newline="") as target:
writer = csv.DictWriter(target, fieldnames=["编号", "备注"])
writer.writeheader()
writer.writerows(records)
示例中的多行备注属于一个字段,writer 负责按方言规则添加必要引号。newline="" 保证文本层不再次改写 writer 产生的换行。不要在 writerow 之后补写换行,也不要手动把每个字段拼接成逗号分隔字符串,否则含逗号、引号或换行的字段会增加转义错误。

如果对接协议要求使用 LF,保留 open 的空字符串设置,并在 writer 上明确设置记录结束符:
import csv
# 对接方明确要求 LF 时,在 writer 上设置记录结束符
with open("export-lf.csv", "w", encoding="utf-8", newline="") as target:
writer = csv.writer(target, lineterminator="\n")
writer.writerow(["编号", "说明"])
writer.writerow(["F-206", "一条记录"])
改变 lineterminator 影响写出的记录边界,不会自动统一字段本身包含的换行。如果业务还要求备注内容统一换行,应在业务字段处理层明确实施,而不是期待 CSV 写入参数顺便清洗内容。
跨平台使用与常见疑问
这个做法适用于 Python 3 标准库 csv 配合文本文件对象读写,也适用于 DictReader、DictWriter。不是只有 Windows 才值得设置:写出重复回车的现象在使用 CRLF 文本转换的平台上更突出,而读取时保留多行字段的原始换行同样有意义。
newline="" 与 newline="\n" 能互换吗?
写入时两者都不进行文本层换行转换,但读取行为不同:后者只按指定的 LF 识别行结束,不等于空字符串启用的通用换行识别。为了保持读写约定一致,我会优先采用 csv 文档推荐的空字符串形式。
已经有空白行,设置参数会自动修复吗?
不会。参数影响本次读写,不会修复已经写入的文件。如果业务要清理历史空记录,应先定义空记录的含义;包含换行的合法字段与真正的空记录不能一概删除。
二进制模式能绕开这个问题吗?
标准 csv.reader 接收字符串迭代,writer 写出文本,直接把 rb 或 wb 文件对象交给它们不符合这套接口。已有二进制流时可以通过 TextIOWrapper 建立文本层,并明确 encoding 与 newline;关闭包装流也会影响底层流的生命周期。
中文乱码或者表头出现 BOM 怎么处理?
这是编码约定的问题,不能靠 newline 修复。与数据来源约定编码;如果已知文件含 UTF-8 BOM,可按实际格式使用 utf-8-sig 读取。不要在不清楚来源时用忽略解码错误掩盖数据损坏。
选择参数时先确认两件事:是否由 csv 模块负责结构,以及对接方要求哪种记录结束符。前者决定文本层保留换行,后者决定 writer 的设置。文本流详细规则见 https://docs.python.org/3/library/io.html#io.TextIOWrapper,open 参数说明见 https://docs.python.org/3/library/functions.html#open。
Python Protocol 怎样表达结构化接口
- 上一篇
- Python Protocol 怎样表达结构化接口
- 下一篇
- Python nullcontext 怎样统一可选上下文管理
-
- 文章 · python教程 | 29分钟前 | 标准库 · 资源管理 · python · Python 上下文管理 contextlib nullcontext
- Python nullcontext 怎样统一可选上下文管理
- 385浏览 收藏
-
- 文章 · python教程 | 33分钟前 | python · 接口设计 · Python 静态类型检查 typing.Protocol 结构化接口
- Python Protocol 怎样表达结构化接口
- 113浏览 收藏
-
- 文章 · python教程 | 33分钟前 | 标准库 · 枚举 · Python教程 · Python unique flag enum.verify EnumCheck CONTINUOUS NAMED_FLAGS
- Python enum.verify 怎样在定义时检查枚举约束
- 323浏览 收藏
-
- 文章 · python教程 | 59分钟前 | Python教程 · 日期时间 · Python zoneinfo TZPATH PYTHONTZPATH 时区数据库
- Python zoneinfo 怎样让进程使用自定义时区数据库
- 135浏览 收藏
-
- 文章 · python教程 | 1小时前 | SQLite · Python教程 · Python SQLite sqlite3 查询结果 sqlite3.Row row_factory
- Python sqlite3 怎样让查询结果按列名访问
- 265浏览 收藏
-
- 文章 · python教程 | 1小时前 | Python enum flag 位运算 IntFlag FlagBoundary
- Python enum.FlagBoundary 怎样处理未知标志位
- 476浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- Python os.splice 怎样在文件描述符之间传输数据
- 156浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- Python TaskGroup 怎样让子任务失败统一收敛
- 501浏览 收藏
-
- 文章 · python教程 | 19小时前 | CLI · python · Python optparse OptionGroup 命令行帮助
- Python optparse.OptionGroup 怎样把旧 CLI 帮助选项分组
- 116浏览 收藏
-
- 文章 · python教程 | 19小时前 | 配置文件 · Python 命令行参数 argparse fromfile_prefix_chars 参数文件
- Python argparse.fromfile_prefix_chars 怎么从参数文件读取长命令
- 151浏览 收藏
-
- 文章 · python教程 | 19小时前 |
- Python Base85 和 Base64 有什么区别,短文本该怎么选
- 365浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 987次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 991次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 1114次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 1083次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 929次使用
-
- Python TaskGroup 怎样让子任务失败统一收敛
- 2026-11-12 501浏览
-
- Python xml.dom.minidom.unlink 怎样释放不再使用的 DOM 树引用
- 2026-10-27 501浏览
-
- Python typing 怎样用 TypeIs 缩小类型
- 2026-10-24 501浏览
-
- Python sqlite3 Connection serialize 怎么导出数据库快照:备份窗口、内存占用与恢复校验
- 2026-08-26 501浏览
-
- Python监控网页状态:requests异常处理实战
- 2026-05-29 501浏览

