可行但易出错:需手动处理节名空格、等号位置、注释、引号值、Unicode编码等;推荐使用轻量无依赖的inih库,配合UTF-8路径与标准化换行处理。

用 std::ifstream 和 std::ofstream 手动解析 INI 文件可行但容易出错
纯 C++ 标准库不提供原生 INI 解析支持,直接用 std::ifstream 逐行读取 + 字符串分割看似简单,实际会踩一堆坑:节名([section])的空格容忍、键值对中等号位置不唯一(key = value / key=value)、注释识别(; 和 #)、引号包裹的值(path = "C:\foo\bar")、Unicode 编码(尤其 Windows 下 ANSI/UTF-8 混用)都得自己处理。
手动实现适合极简场景(如仅读几个固定 key),但一旦配置项变多、格式稍不规范,find('=') 就可能切错位置,或把注释当有效行。
- 不要依赖
std::getline后用substr硬切——等号前后的空格必须 trim,且要跳过整行注释 - 节名匹配建议用正则
\\[([^\\]]+)\\],而非简单找方括号——避免误匹配值里的[abc] - 写入时别用
operator 直接拼接,否则中文路径或含空格的值会丢失引号,导致下次读取失败
推荐用 inih 库:轻量、无依赖、头文件即用
inih(INI Not Invented Here)是 C 写的单头文件库,C++ 项目可直接 #include,体积小、无外部依赖、线程安全,且明确支持 UTF-8。它不封装成类,而是提供回调函数接口,避免内存拷贝开销。
典型用法:ini_parse("config.ini", handler, &user_data),其中 handler 是你定义的函数,接收 section、name、value 三个 const char* 参数。
立即学习“C++免费学习笔记(深入)”;
- 读取布尔值需自己转换:
strcmp(value, "true") == 0 || strcmp(value, "1") == 0 - 若配置文件路径含中文,Windows 下需先用
MultiByteToWideChar转 UTF-16,再转 UTF-8;Linux/macOS 一般直接传 UTF-8 路径即可 - 写入功能需自行实现——
inii(inih的配套 C++ 封装)提供了INIWriter类,但非官方,需额外引入
写入 INI 文件时,std::ofstream 默认不覆盖换行风格,Windows 上易出 \r\n 乱码
用 std::ofstream 写 INI 时,如果在 Windows 编译但目标部署在 Linux,或反之,换行符不一致会导致解析失败(某些解析器严格按 \n 分割)。更隐蔽的问题是:二进制模式写入才能保证 \r\n 不被自动转换,但文本模式下 std::endl 会强制插入平台默认换行。
- 统一用
"\n"字面量写换行,禁用std::endl - 打开文件时显式指定
std::ios::out | std::ios::binary,避免流缓冲区做 CR/LF 转换 - 写入节名和键值对前,确保字符串已 utf8_encode(如有中文),不要依赖 locale
跨平台部署时,GetModuleFileName 和 argv[0] 获取配置路径的行为差异很大
Windows 下常用 GetModuleFileName 取 exe 所在目录拼 "config.ini";Linux/macOS 得靠 argv[0] + readlink("/proc/self/exe") 或 _NSGetExecutablePath。两者返回路径格式不同(Windows 是 C:\\app\\,Linux 是 /usr/local/bin/),硬拼接易出错。
更稳妥的方式是:优先检查当前工作目录(getcwd),再 fallback 到可执行文件同级目录,并统一用 / 作分隔符(std::filesystem::path 在 C++17 后可自动 normalize)。
- 不要用
strcat拼路径——用std::filesystem::path("config.ini").lexically_normal() - 配置文件不存在时,先尝试创建空文件再写入默认值,避免首次运行就因读取失败崩溃
- 权限问题常被忽略:Linux 下若程序以 root 启动后降权,生成的 config 文件可能属主为 root,普通用户后续无法修改











