WritePrivateProfileString是Windows下最轻量的INI写入方式,需用绝对路径、注意编码与线程安全;跨平台应选inih等库手动写入,避免硬依赖API。

用 WritePrivateProfileString 写入 INI 文件最直接
Windows 平台下,WritePrivateProfileString 是最轻量、无需第三方依赖的写入方式。它直接调用系统 API,写入格式严格遵循传统 INI 结构([section]、key=value),适合简单配置持久化。
常见错误现象:WritePrivateProfileString 返回非零但文件没变化——大概率是路径含中文或权限不足;返回 0 却没报错?检查传入的 lpFileName 是否为绝对路径,相对路径默认按当前工作目录解析,极易出错。
- 必须用绝对路径,例如
"C:\MyApp\config.ini",不能只写"config.ini" - section 名区分大小写,但 key 不区分;重复写入同 section+key 会覆盖而非追加
- 如果值为空字符串(
NULL或空指针),该 key 会被删除;若想清空值,传""(空字符串) - 写入后系统不保证立即落盘,关键配置建议后续调用
FlushFileBuffers(需先用CreateFile打开文件句柄)
跨平台方案得自己解析再写,别硬套 Windows API
Linux/macOS 没有 WritePrivateProfileString,强行用 Wine 或条件编译会让代码脆弱。更实际的做法是:用轻量解析库(如 inih)读取,修改内存结构,再手动生成文本写回。
使用场景:需要部署到 Docker 容器、CI 构建机或 macOS 开发环境时,硬依赖 Windows API 会导致编译失败或运行时崩溃。
立即学习“C++免费学习笔记(深入)”;
-
inih只读,不提供写功能,得自己拼接字符串——注意 section 名两边要加[],key/value 中的等号前后不加空格(部分解析器对空格敏感) - 写入前务必以
std::ios::out | std::ios::trunc模式打开文件,避免残留旧内容 - 换行符统一用
" "(LF),别用" "(CRLF),否则 Linux 下可能被某些工具误判为损坏 - 如果配置项含特殊字符(如
=、[、]),INI 标准不支持转义,要么改格式(换 JSON),要么提前过滤/替换
多线程写 INI 文件必须加锁,否则内容会乱
INI 是纯文本,没有任何原子写入机制。WritePrivateProfileString 本身不是线程安全的,多个线程同时调用可能造成 section 错位、key 覆盖丢失、甚至整个文件变空。
性能影响:加锁本身开销小,但若频繁写配置(比如每秒多次),瓶颈会从磁盘 I/O 变成锁竞争。
- 不要依赖“写得少就没事”——即使两个线程各写不同 section,文件重写过程仍可能交叉
- 推荐用全局互斥量(如
std::mutex),在每次调用WritePrivateProfileString前 lock,返回后 unlock - 如果只是偶尔更新(如程序退出前保存),且确定无并发,可省略锁;但只要存在后台线程或信号处理,就必须考虑
修改 INI 时别忽略 BOM 和编码问题
Windows 记事本默认用 UTF-16 LE + BOM 创建 INI,而 WritePrivateProfileString 总是按当前系统 ANSI 代码页(如 GBK)写入。结果就是:中文在记事本里显示正常,用 VS Code 打开却成乱码;或者反过来。
容易踩的坑:用 Notepad++ 改完配置后程序读不出来——其实是编码不一致导致 GetPrivateProfileString 解析失败,连带写入也失效。
-
WritePrivateProfileString不支持 UTF-8 / UTF-16,只认系统默认 ANSI 编码;如需 Unicode,必须用WritePrivateProfileStringW(宽字符版),且文件本身必须是 UTF-16 LE + BOM - 若用
fopen+fwrite手动写,务必确认文件打开模式匹配编码,例如写 UTF-8 用"wb",写 UTF-16 LE 用"wb"并手动写 BOM(ÿþ) - 配置文件一旦用了 UTF-16,所有读写操作都必须统一宽字符 API,混用 ANSI 版本必出错
真正麻烦的不是怎么写,而是怎么让所有环节——编辑、读取、写入、部署——用同一套编码逻辑。多数项目最后都干脆避开中文 key/value,或者直接切 JSON。INI 看似简单,编码和并发这两块,漏掉一个就等于埋雷。



















