登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  python教程

Python csv 文件为什么要用 newline 空字符串打开

来源:17golang原创

时间:2026-11-12 02:45:09 280浏览 收藏

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 的引号规则区分字段内容和结构字符直接按行切分也能完整解析
文本换行设置与CSV解析职责的分组关系
结构说明图:文件字节与文本流属于输入边界,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 之后补写换行,也不要手动把每个字段拼接成逗号分隔字符串,否则含逗号、引号或换行的字段会增加转义错误。

CSV writer与文本层换行设置的静态关系
结构说明图:记录结束符受 writer 设置约束,文本层受 newline 设置约束,编码决定文件字节表达;这三个配置承担不同责任。

如果对接协议要求使用 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。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>