直接用fstream读写csv最稳妥,但需手动处理转义;简单场景可用ifstream逐行+stringstream切分;复杂csv应使用csv-parser等rfc 4180兼容库;写入时仅必要字段加引号并转义双引号。

CSV 文件没有统一标准,C++ 标准库也不提供原生支持,直接用 fstream 读写最稳妥,但必须自己处理引号、换行、逗号转义等边界情况。
用 std::ifstream 逐行读取 + 手动切分,适用于简单 CSV(无嵌入逗号/换行/双引号)
这是最快上手的方式,适合配置表、日志导出等结构干净的场景。核心是按行读,再用 std::stringstream 和 std::getline 按逗号分割:
std::ifstream file("data.csv");
std::string line;
while (std::getline(file, line)) {
std::stringstream ss(line);
std::string cell;
std::vector<std::string> row;
while (std::getline(ss, cell, ',')) {
row.push_back(cell);
}
// 处理 row
}
- 不处理字段内含逗号(如
"Smith, John")、换行或双引号转义 - 空字段(
,,)会被正确识别为空字符串 - 首尾空格不会自动 trim,需手动调用
std::string::find_first_not_of等清理
用第三方库 csv-parser(by ben-strasser)解析带引号和换行的 CSV
当数据来自 Excel 或用户上传,且可能含 "Alice""s cat" 或跨行字段时,必须用成熟解析器。csv-parser 是 header-only、轻量、符合 RFC 4180 的选择:
#include "csv.hpp"
...
io::CSVReader<3> in("data.csv");
std::string name; int age; double salary;
while (in.read_row(name, age, salary)) {
// 自动去引号、处理转义、跳过 BOM
}
- 默认以 UTF-8 读取,不支持 GBK;若文件含 BOM,它会自动跳过
- 列数必须编译期确定(模板参数),动态列需改用
io::CSVReader+get_col_names()和get_row() - 遇到格式错误(如引号不匹配)会抛
std::runtime_error,建议用try/catch包裹
用 std::ofstream 写 CSV:何时加引号、何时转义
写入比读取更容易出错——不是所有字段都要加双引号,只有必要时才加,并且内部双引号要变成两个:
立即学习“C++免费学习笔记(深入)”;
- 字段含逗号、换行符或开头/结尾是空格 → 必须用双引号包裹
- 字段本身含双引号 → 每个双引号替换成两个双引号(
"→"") - 其他情况(纯数字、纯字母)可不加引号,但加了也合法
示例写法:
std::ofstream out("out.csv");
auto escape = [](const std::string& s) -> std::string {
if (s.find_first_of(",\"\n\r") == std::string::npos &&
(s.empty() || !std::isspace(s.front()) || !std::isspace(s.back()))) {
return s;
}
std::string escaped = "\"";
for (char c : s) {
if (c == '"') escaped += "\"";
escaped += c;
}
escaped += "\"";
return escaped;
};
out << escape("Name") << "," << escape("City") << "\n";
out << escape("O'Reilly") << "," << escape("New \"York\" City") << "\n";
中文路径、UTF-8 BOM 和 locale 问题
Windows 下用 std::ifstream 打开含中文路径的 CSV 会失败,因为 C++ 标准流不接受宽字符路径:
- Windows:改用
_wfopen+fopen_s或 Boost.Iostreams 的wpath支持 - Linux/macOS:路径本身 UTF-8 编码即可,无需额外处理
- 写入含中文的 CSV 时,务必在文件开头写入 UTF-8 BOM(
\xEF\xBB\xBF),否则 Excel 默认用 ANSI 打开乱码 -
std::locale::global(std::locale(""))可能干扰数字格式(如小数点变逗号),不建议全局设置
真正麻烦的从来不是“怎么读”,而是“怎么让 Excel、Python pandas、R 和你自己的 C++ 程序对同一份 CSV 达成一致”——多花十分钟验证引号规则和 BOM,能省掉几小时排查乱码和截断问题。











