直接fputs硬拼字符串易违反INI隐含规则,导致API拒绝读取;应优先用WritePrivateProfileString(注意节名不加括号、NULL参数语义、绝对路径),跨平台需严格处理节重复、空行及特殊字符。

INI写入为什么不能直接用fputs硬拼字符串?
因为INI格式有隐含规则:节名必须用[section]包裹、键值对不能含多余空格、注释行以分号开头、空行需保留。手动拼接容易漏掉转义(比如值里含=或换行)、节名重复时覆盖逻辑难控制、Windows下换行用
而Linux用
——直接fputs写会生成非法INI,被GetPrivateProfileString等API拒绝读取。
用WritePrivateProfileString写入最省事但有坑
Windows API提供现成函数,无需解析,但要注意四点:
-
lpAppName传"SectionName"即可,不用加方括号 -
lpKeyName为NULL时清空整个节(慎用) -
lpString为NULL时删除该键(不是写空字符串) - 路径必须是绝对路径,相对路径会被解析为当前进程工作目录,常导致写到错位置
示例:
WritePrivateProfileString("database", "host", "127.0.0.1", "C:\app\config.ini");
跨平台手写INI写入要处理三类内容
核心是按“节→键→值”逐层写,且必须严格控制换行和空格:
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
立即学习“C++免费学习笔记(深入)”;
- 节名写入前检查是否已存在,避免重复节(可先读再合并,或用
std::map<std::string, std::map<std::string, std::string>>内存建模) - 键名/值中若含
=、;、[、]不需转义,但值两端不加引号(INI标准不支持引号包裹) - 每节后必须写一个空行(否则多节连在一起会被误认为同一节)
简版实现关键片段:
std::ofstream f("config.ini");<br>f << "[network]
";<br>f << "port = 8080
";<br>f << "timeout = 30
"; // 注意这里两个
<br>f << "[log]
";<br>f << "level = debug
";
写入后立即读取失败?检查文件编码和BOM
用std::ofstream默认写的是ANSI(系统本地编码),但某些INI解析器(如Qt的QSettings)默认按UTF-8读。若值含中文,写入ANSI而读取UTF-8会导致乱码甚至解析中断。解决方案:
- Windows下用
std::wofstream配合imbue设为UTF-8 locale(需C++11以上) - 更稳妥做法:用
WritePrivateProfileString(它内部自动处理编码) - 或手动在文件头写UTF-8 BOM:
,但注意部分旧工具会把BOM当无效字符跳过
真正麻烦的不是怎么写,而是写完要不要校验——尤其当配置被多个线程/进程并发修改时,fstream不带原子写入,可能写一半被中断,留下截断文件。

















