ini文件解析需权衡平台与功能:windows可用系统api但不跨平台;推荐mini_ini或inih库,轻量且无依赖;手写需处理换行、空格、注释等边界;写入须保证原子性并统一utf-8编码。

没有标准库支持,得靠第三方库或自己解析;Windows 下可用 GetPrivateProfileString / WritePrivateProfileString,但跨平台不可用,且不支持注释、多段同名、嵌套等常见需求。
Windows API 直接读写 INI 文件(仅限 Win32)
如果你只在 Windows 上跑,且配置项极简单(无空格、无特殊字符、无重复 section),GetPrivateProfileString 和 WritePrivateProfileString 是最轻量的选择。它们直接调用系统 API,无需额外依赖。
- 读取时若键不存在,返回默认字符串(不能区分“键不存在”和“值为空”)
- 写入会自动创建文件,但不会保留原有注释、空行或顺序
- 路径必须是绝对路径或当前工作目录下的相对路径;中文路径需确保
MultiByteToWideChar正确转换(ANSI 版本易乱码) - 示例:读取
[network]\nport=8080中的 port:char buf[256] = {0};<br>GetPrivateProfileStringA("network", "port", "0", buf, sizeof(buf), "config.ini");
推荐用 mini_ini 或 inih 实现跨平台解析
这两个是纯 C 的轻量级库,头文件即用,无编译依赖,C++ 项目里只需 #include + 链接一个 .c 文件(或直接把源码加进工程)。相比 Boost.PropertyTree,它们不引入 STL 容器依赖,内存占用低,适合嵌入式或资源敏感场景。
-
inih更活跃,支持回调式解析(适合大文件流式处理),但不直接提供写入函数;需自己拼接字符串再写文件 -
mini_ini提供ini_gets/ini_puts,读写对称,但不支持 Unicode 路径(Windows 下需用ini_getws配合 UTF-16) - 二者都不解析
include=xxx.ini或变量插值(如root_dir=%APPDATA%),这类逻辑得自己补 - 注意 section 名和 key 名默认区分大小写(
inih可通过宏关闭)
手写简易解析器要注意的边界情况
如果项目不允许引入任何外部代码,又需要基本兼容性(比如支持分号注释、空行、引号包裹值),手写解析器比想象中容易出错。
- 值中的等号(
url=https://example.com/path?k=v)必须只取第一个等号左边为 key,右边全部为 value —— 不能用std::string::find_last_of('=') - 换行符可能是
\r\n(Windows)、\n(Linux)或\r(旧 Mac),统一用\n切割后 trim\r - section 行格式为
[name],但实际常见[ name ]或[name ],需 trim 空格后再匹配方括号 - 忽略以
;或#开头的整行(包括前导空格),但key=value ; comment这种行内注释不建议支持,会增加状态机复杂度
写入 INI 时顺序、编码与原子性问题
INI 不是数据库,写入操作天然不具备原子性。直接 fopen(..., "w") 覆盖会导致进程崩溃时配置丢失;同时多个进程写同一文件会相互覆盖。
- 写入前先备份原文件(如
config.ini.bak),失败时可回退 - 新内容写入临时文件(如
config.ini.tmp),rename()替换原文件(POSIX)或MoveFileEx(Windows)保证原子性 - 编码统一用 UTF-8(无 BOM);Windows 记事本打开乱码是因为它默认用 ANSI,不是你的错
- 不要试图保持原有注释/空行顺序 —— 手动维护成本远高于收益;真有此需求,改用 JSON 或 TOML
真正麻烦的从来不是读写逻辑本身,而是「谁在什么时候改了哪一行」—— 没有锁、没有版本、没有 diff,多人协作改同一个 INI 时,冲突只能靠人工肉眼合并。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











