读CSV必须用std::getline配合手动状态机,仅在outside_quotes时以逗号分隔,引号内内容原样保留,并处理BOM、换行符、转义及跨行字段。

std::getline + 手动状态机是读 CSV 的底线能力
别指望 std::stringstream 配合 std::getline(ss, field, ',') 能正确处理真实 CSV。只要字段里有 "Smith, Jr." 或 "He said ""Hi"".",它就直接切错。必须逐字符扫描、维护引号状态。
- 状态只分三种:
outside_quotes、inside_quotes、escaped(用于识别连续两个") - 遇到
"时:若当前在outside_quotes→ 切换到inside_quotes;若已在inside_quotes且下一个是"→ 进入escaped并跳过下一个" - 逗号仅在
outside_quotes时才作为分隔符;引号内所有字符(包括,和\n)都原样保留 -
std::getline(file, line)读完后,记得先调line.erase(std::remove(line.begin(), line.end(), '\r'), line.end())清掉 Windows 换行残留
写 CSV 必须自己加引号和转义,不能无脑 << value << ","
直接输出 name 会把 <code>"Alice, Jr." 写成 Alice, Jr.,25,Excel 打开就错位。写入前必须判断字段是否需包裹:
- 字段含
,、"、\n或首尾空格 → 必须用双引号包裹 - 字段内有
"→ 替换为""(两个双引号),再包进外层引号,如"He said ""Hi""." - 字段为空字符串
""或全空白 → 仍需输出一对引号"",否则 Excel 会吞掉空列 - 不要用
std::endl换行,统一用"\n";Windows 下若需\r\n,显式写"\r\n"
中文路径和 UTF-8 BOM 是 Windows 下最常卡住的两个点
在 Windows 上,std::ifstream 打不开带中文路径的文件,或读出乱码,几乎全是同步机制和编码处理没关对。
- 打开前加
std::ios::sync_with_stdio(false),否则宽路径或 UTF-8 内容会被截断或失败 - 文件开头有 BOM(
0xEF 0xBB 0xBF)?读第一行前检查:if (line.size() >= 3 && line[0] == '\xEF' && line[1] == '\xBB' && line[2] == '\xBF') line = line.substr(3); - Linux/macOS 通常没问题,但 Excel 导出的 CSV 在 Windows 下大概率带 BOM,不跳过会导致首字段解析失败
- 路径含中文?C++17 起推荐用
std::filesystem::path(fname).string()构造,确保传给std::ifstream的是合法 UTF-8 字节序列
大文件别全 load 进内存,流式处理才是正解
10 万行 × 50 列的 CSV,每个字段平均 20 字节,光 std::string 对象就占几百 MB。真要解析,得边读边处理,别存整个 std::vector<:vector>></:vector>。
立即学习“C++免费学习笔记(深入)”;
- 用
while (std::getline(file, line)) { parse_line(line); process(fields); }流式推进 - 字段转数字前务必先 trim:用
field.find_first_not_of(" \t\r\n")和find_last_not_of截出有效子串;空或全空白字段不能直接喂给std::stoi - 需要数值类型?优先用
std::from_chars(C++17),它不抛异常、不依赖 locale、性能好;std::stoi必须包try/catch - Excel 导出的欧洲格式(小数点用逗号)?
std::stod会崩,要么预处理替换","→".",要么用std::stringstream配合自定义std::locale,但注意多线程下 locale 不安全



















