CSV文件明明有4行,为什么数据只有2条?用Python的csv.reader区分“物理行”与“记录”

プログラミング・Web開発カテゴリを表すパンダのイラスト 编程・Web开发

关于本文
本文是通过利用生成式AI的自动化生成流程创建的。基于Python官方CSV规范以及现有Daily Code样本的验证记录,使用虚拟CSV来解释物理行数和记录数的区别。这是从P1到P5这5个视角的自我审查,并非独立的AI审查。

验证状态:🧪 现有样本的Linux/Python 3.13.5测试记录已通过12项。文章发布环境、Windows/macOS未经验证

CSV文件明明有4行,为什么数据只有2条?用Python的csv.reader区分“物理行”与“记录”

打开CSV文件时明明看到4行,但导入的数据却只有2条。这并不一定意味着数据丢失或读取失败。这是因为被引号包围的单元格内包含换行符,导致文件中的多行在CSV中构成了单个记录csv.reader。使用Python标准库的该功能,可以在不破坏包含换行符的单元格的前提下正确统计数据量。

什么时候会遇到麻烦

当咨询列表或问卷调查结果导出为CSV时,“备注”、“自由文本”或“工作便签”等字段可能会包含换行符。如果监控人员只看文本编辑器的行号或对应的值就断定“导入的数据量不够”,就会把实际上正常的CSV误认为是故障。相反,将引号损坏的CSV当作正常文件处理也是危险的。wc -l为了理解这种差异,我们需要区分以下三个概念。

统计对象

本次的含义注意事项物理行
由文件中的换行符分隔的显示行也包含引号内部的换行符CSV记录
CSV 记录CSV 解析器返回的一行数据可能会跨越多个物理行
数据条数CSV 记录数减去 1 个表头后的数量是否有表头需要根据具体业务进行确认

本教程假定“必然包含 1 个表头的 UTF-8 CSV”。由于并非所有的 CSV 都带有表头,因此一般的 CSV 总记录数与此处给出的 CSV_RECORDS 并不完全等同。

首先来看一个虚拟的 CSV

示例 demo.csv 的内容如下。只有 A 的备注栏占据了两行。

id,note
A,"line1
line2"
B,done

在文本上虽然有 4 行,但按照 CSV 的解析方式,它包含表头、A 和 B 共 3 条记录。如果只看数据,则是 A 和 B 共计 2 条。A 的 note 单元格包含了 line1 和 line2 之间的换行符。引号用于将包含逗号或换行符的值表示为一个完整的字段。

如果单纯地按行分割字符串,可能会把 A 备注的后半部分误认为是新记录。CSV 并不是单纯的“以逗号分隔的行”的集合,而是一种需要正确解析引号的格式。这就是为什么不使用自己编写的 split(',') 来导入数据的原因。

准备与执行步骤

无需额外安装软件包。本教程假定环境为 Python 3.9 或更高版本。本次实际测试是在 Python 3.13.5 下进行的。代码、测试、虚拟 CSV 以及 README 已打包在文章末尾的 GitHub 示例中。

  1. 获取示例文件夹,并将audit_csv.py、demo.csv、test_audit_csv.py放在同一个文件夹中。

  2. 打开终端,并切换到该文件夹。

  3. 依次执行以下命令。

python3 --version
python3 audit_csv.py demo.csv
python3 -m unittest discover -p 'test_*.py' -v

如果在 Windows 中无法识别 python3,请检查 Python 的安装状态,并尝试使用 py -3。目前尚未在 Windows 上实测过执行相同的命令。请注意不要混淆 PowerShell 和 Bash 的命令,首先应确认版本显示是否正常。

本次在 Linux/Python 3.13.5 下实测的 CLI 输出如下。

STATUS=OK
PHYSICAL_LINES=4
CSV_RECORDS=2
HEADER_COLUMNS=2
MULTILINE_RECORDS=1

PHYSICAL_LINES=4表示显示上的 4 行,CSV_RECORDS=2则意味着除表头外有 2 条记录。MULTILINE_RECORDS=1表示存在 1 条跨越多个物理行的 数据记录。即使数值不同,也不一定意味着异常。

Python 是如何进行区分的

本教程的核心是 Python 标准库的 csv.reader。提取出关键部分后代码如下。

import csv

with open('demo.csv', encoding='utf-8-sig', newline='') as file:
    reader = csv.reader(file, strict=True)
    header = next(reader)
    records = sum(1 for row in reader)
    print('データ件数:', records)

newline=''用于将换行符的处理交由 CSV 解析器负责。Python 官方文档也说明了在打开 CSV 文件时应指定此参数。utf-8-sig用于正确读取带 BOM 的 UTF-8 文件。这并不是自动识别字符编码,因此不保证能够读取 Shift_JIS 等编码的文件。

next(reader)将第一条 CSV 记录提取为表头。随后的循环中计数的不是文本的换行数,而是解析器返回的数据记录条数。strict=True是一个旨在让不规范的 CSV 格式更容易报错的设置,但它不会检查业务字段的值是否正确。

官方规范中包含reader.line_num 属性。如果只看名字,很容易让人觉得是“第几条数据”,但实际上它是从原始输入中读取的物理行位置。如果引号内包含换行符,它就会与记录数不一致。在教材的完整版中,会通过与前一个 line_num 进行比较,来统计跨越多行的数据记录。

只改变一个条件时的结果会怎样

制作一个将A的备注合并为一行的同名CSV文件,而保留原本的 demo.csv 不变。

id,note
A,line1
B,done

这种情况下,其期望值(修改后的该文件本次未实际运行) 为 PHYSICAL_LINES=3、CSV_RECORDS=2、MULTILINE_RECORDS=0。数据条数保持不变,只有物理行数减少了1。通过这一对比可以发现,仅凭物理行数的增减无法判断数据的增减。

另外,即使是在Windows中常见的CRLF换行符,教材也会将 \r\n 视为一个物理换行来统计。CRLF的情况已经在单元测试中执行过。不过,这并不是一个能够自动识别所有字符编码或分隔符不同的CSV的程序。

失败时确认退出代码和原因

完整版不会在标准输出中显示CSV的内容或实际文件路径,而是仅输出数值和错误类型。使用虚拟文件进行测试的结果如下。

情况输出示例退出代码确认事项
正常的CSVSTATUS=OK0是否存在表头及预期条目数
列数不匹配ISSUE=FIELD_COUNT_MISMATCH2逗号、引号、原始数据格式
引号未闭合或非法的 UTF-8ISSUE=PARSE_OR_ENCODING_ERROR2文件格式与字符编码
文件不存在或无法读取ISSUE=READ_ERROR3指定路径、权限、文件是否存在
文件超过 1MiBISSUE=TOO_LARGE3教程的大小限制

在本次测试中,诸如正常文件、CRLF、BOM、无末尾换行、空文件、列数不一致、引号漏闭合、非法 UTF-8、文件不存在、超出大小等全部 12 项均已成功。python3 -m py_compile 也已经成功。执行环境为隔离的 Linux 容器,并非操作 Ubuntu 生产环境或 WordPress 的结果。

当没有文件时,会输出 STATUS=READ_ERROR ISSUE=READ_ERROR 并以退出码 3 结束,这一点已通过 CLI 进行了确认。若要将其整合到自动化处理中,请针对输出内容 STATUS=OK不仅要检查是否存在,还要判断退出代码是否为0。如果即使失败也继续执行后续工序,那么无法确认记录数这一问题本身就会被忽视。

在实际工作中应用前需要了解的事项

本教程处理的是将1MiB以下的UTF-8 CSV读取到内存中的只读检查。在处理巨大文件的用途中,则需要流式读取或其他大小控制。此外,即使列数一致,也无法证明诸如“订单号没有重复”、“日期正确”、“金额合理”等业务上的质量。列名重复和类型检查也是其他需要解决的课题。

物理行数的比较非常适合作为当被咨询“导入记录数异常”时的初步排查手段。首先应确认输入CSV的格式、表头、引号内的换行符以及字符编码,然后计算实际的CSV记录数。自然的顺序是在这之后再确认导入目标位置的排除条件、去重以及错误行的处理方式。

没有必要将真实客户的CSV直接发送给AI或外部服务。如果能像本次这样用虚拟的两条数据重现原因,就可以在不使用机密信息的情况下理解其机制。即使设计上不在日志中输出文件内容,在实际运用于生产环境之前也务必确认日志的保存路径和权限。

总结

CSV的“4行”与“2条记录”是可以同时成立的,因为csv.reader会将用引号括起来的单元格内的换行符解释为单个记录的一部分。在确认CSV记录数时,请区分物理行和逻辑记录,并明确表头的处理方式。newline='',只要备齐字符编码指定以及异常情况的退出代码,对导入故障的说明就会变得更加具体。

官方资料与一手信息

GitHub 示例

文档信息

文章??
CSV文件明明有4行,为什么数据只有2条?用Python的csv.reader区分“物理行”与“记录”
?布日期
更新日期
来源
https://papanda925.com/?p=18272&lang=zh

?可: ?于本站?有相??利的正文及原??表,除非?有?明,可依据 CC BY 4.0 使用。本文可能包含使用生成式AI?建或??的内容。若代??有?可声明,或?接的GitHub???定了?可,?代?以??可?准。引用内容、第三方?料、?片及商?不在本?可范?内。 使用政策

标题和URL已复制