应逐字段转字符串后拼接写入,不可直接write结构体地址或用

用 std::ofstream 逐行写入结构体字段,别用二进制或序列化
CSV 是纯文本格式,必须把结构体每个字段转成字符串再拼接。直接 write() 结构体地址会写入乱码或不可读字节,且跨平台时字节序、内存对齐都可能出错。std::ofstream 是最轻量、最可控的选择,无需第三方库。
常见错误是试图用 operator 一次性输出整个结构体——C++ 默认不支持,会编译失败。必须显式提取字段:
struct Person {
std::string name;
int age;
double salary;
};
std::ofstream file("data.csv");
file
<h3>字符串字段含逗号、换行或引号时,必须加双引号并转义内部引号</h3>
<p>CSV 规范要求:若字段含 <code>,</code>、<code>\n</code> 或 <code>"</code>,必须用双引号包裹;若字段本身含双引号,需用两个双引号表示(如 <code>"He said ""Hi"""</code>)。不处理会导致 Excel 打开错列、数据截断。</p>
<p>不要手写字符串拼接逻辑,容易漏转义。推荐封装一个安全的转义函数:</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill3052" title="csv to excel"><img
src="https://img.php.cn/upload/skill/000/000/081/178945026685484.jpg" alt="csv to excel" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill3052" title="csv to excel" class="overflowclass">csv to excel</a>
<p class="overflowclass">将CSV文件转换为支持中文字符、自动格式化、多工作表的专业Excel工作簿。</p>
</div>
<a rel="nofollow" href="/xiazai/skill3052" title="csv to excel" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
<pre class="brush:php;toolbar:false;">std::string csv_escape(const std::string& s) {
if (s.find_first_of(",\"\n") == std::string::npos) return s;
std::string out = "\"";
for (char c : s) {
if (c == '"') out += "\"\"";
else out += c;
}
out += "\"";
return out;
}
// 使用:
file
- 空字符串也要转义(
""),否则某些解析器会当成缺失字段 - 避免用
std::regex_replace做转义——小字符串下性能差,且正则引擎在嵌入式或旧编译器上可能不可用
数值字段用 std::fixed 和 std::setprecision 控制小数位,避免科学计数法
默认浮点输出可能变成 1.23e+06,Excel 或 Python 的 pandas.read_csv() 会当成字符串而非数字。必须强制固定格式:
#include <iomanip> file <ul> <li> <code>std::setprecision</code> 对整数无影响,但会影响后续所有浮点输出,建议写完立即恢复默认浮点格式(如用 <code>std::defaultfloat</code>)</li> <li>整数字段(如 <code>int</code>)无需设置,但注意负数和零值是否符合业务预期(比如年龄为 <code>0</code> 是否合法)</li> <li>时间戳建议先转成 <code>std::string</code> 格式(如 <code>%Y-%m-%d %H:%M:%S</code>),别直接写 <code>time_t</code> 数值——可读性差,且不同系统 <code>time_t</code> 类型宽度可能不同</li> </ul> <h3>写入后必须检查 <code>file.fail()</code>,尤其在嵌入式或磁盘满场景下</h3> <p>文件写入失败不会抛异常(默认 <code>std::ios_base::failbit</code> 未置位),<code>file 表达式返回流对象,表面看“成功”了,实际可能只写了部分字节或根本没写入。磁盘满、权限不足、路径不存在都会静默失败。</code></p> <p>正确做法是每次关键写入后检查状态:</p> <pre class="brush:php;toolbar:false;">file
- 不要只在最后
file.close()时检查——缓存未刷盘前close()才真正报错,此时已无法定位哪一行出问题 - Windows 下路径含中文时,
std::ofstream默认用本地 ANSI 编码打开文件,可能导致乱码;如需 UTF-8,得用std::wofstream+std::codecvt_utf8(C++17 起已弃用)或直接写 UTF-8 BOM 字节(\xEF\xBB\xBF)并确保编辑器识别
rapidcsv 这类 header-only 库,也别硬写通用序列化逻辑。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










