CSV读取静默截断主因是\x00或\x1a等控制字符被当EOF;需用二进制模式预清理字节,再解码,而非依赖pandas参数或编码设置。
CSV读取时突然截断,大概率是\x00或\x03这类控制字符在捣鬼
python的pandas.read_csv()和csv.reader默认把\x00(空字节)当文件结束符,遇到就直接停——不是报错,是静默截断,所以你查数据长度、看最后几行都对不上。windows记事本另存为utf-8带bom的文件也常混入\ufeff,可能被误解析成非法字符触发异常。
实操建议:
- 先用
head -c 1000 your_file.csv | hexdump -C(Linux/macOS)或Get-Content -Path your_file.csv -Encoding Byte -TotalCount 500 | ForEach-Object { $_.ToString("X2") }(PowerShell)快速扫前几百字节,找00、03、04、1a这类值 - 别依赖
encoding='utf-8'硬扛——控制字符跟编码无关,是二进制层面的中断信号 - 如果确认是
\x00,优先考虑预清理,而不是调参数硬读
用open()手动预清理比改read_csv()参数更可靠
pandas.read_csv()的error_bad_lines=False(旧版)或on_bad_lines='skip'(新版)只跳过解析失败的整行,对文件流里嵌入的\x00完全无效;low_memory=False也救不了——它只影响类型推断,不碰底层字节流。
实操建议:
- 用
open(file, 'rb')读原始字节,.replace(b'\x00', b'')干掉空字节,再用.decode('utf-8', errors='replace')转字符串(errors='replace'把无法解码的字节变,比崩掉强) - 写回临时文件再交给
pandas,别试图把清理后字符串塞进StringIO再读——某些特殊组合(如\r\x00\n)可能导致行计数错乱 - 示例片段:
with open('raw.csv', 'rb') as f: cleaned = f.read().replace(b'\x00', b'') with open('clean.csv', 'w', encoding='utf-8') as f: f.write(cleaned.decode('utf-8', errors='replace'))
真要调读取字节设定,得从csv模块底层下手
如果你必须流式处理超大CSV且不能落地临时文件,就得绕过pandas,用csv模块配io.TextIOWrapper控制缓冲行为。但注意:csv.reader本身不接受buffering参数,真正起作用的是它包裹的TextIOWrapper。
使用 qbo-mileage CLI 及用户凭证,从 Airtable、Outlook 或 Google Calendar 记录生成 QuickBooks Online 里程 CSV 文件。
实操建议:
- 用
open(file, 'rb')+io.TextIOWrapper(f, encoding='utf-8', errors='replace', line_buffering=True)构造可读流 -
line_buffering=True让换行符成为实际分界点,减少因控制字符导致的“半行读取”;但别设buffering=1——那是行缓冲,不是实时刷,意义不大 - 仍需在
csv.reader()外加一层循环,对每行row[0].replace('\x00', '')做字段级清理,因为TextIOWrapper的errors='replace'只管解码错误,不管已解码字符串里的控制字符
Excel导出的CSV最容易藏\x1a(SUB字符),Windows记事本会把它当EOF
Excel保存为CSV时,若单元格内容含不可见字符(比如从网页复制来的软回车、零宽空格),或列中混有二进制数据(极少见但存在),可能插入\x1a。Windows系统级API(包括notepad.exe)看到这个字节就认为文件结束了,所以你用记事本打开只看到一半,pandas读出来也少一半——但它其实没报错,只是读到\x1a就停了。
实操建议:
- 检查是否用
notepad打开过该文件并重新保存过——这是最常见污染源,重保存会固化\x1a - 清理时别漏掉
b'\x1a':.replace(b'\x00', b'').replace(b'\x1a', b'') - 如果源头可控,让Excel用户改用“另存为 → CSV UTF-8(逗号分隔)(*.csv)”而非“CSV(逗号分隔)”,前者基本不插
\x1a
\x00或\x1a,所有基于文本流的解析逻辑都会提前终止——这不是bug,是设计使然。

















