最直接方案是用std::ifstream/std::ofstream按行读写键值对:逐行getline、trim、跳过空行和#注释,用find('=')分割,std::map存储,读取时转小写统一key,数值转换需try/catch校验。

用 std::ifstream 和 std::ofstream 读写键值对 txt 配置最直接
不需要第三方库,C++ 标准库就能搞定简单配置——前提是格式规整、无嵌套、不追求类型安全。核心思路是:按行读取,用 = 或空格分隔键和值,手动解析字符串。
常见错误现象:std::getline 读到空行后后续读取错位;operator>> 跳过空白但吃掉换行符,导致下一行读不全;没处理首尾空格,"port = 8080" 解析出键是 "port "(带空格)。
- 始终用
std::getline逐行读,避免>>的空白符副作用 - 每行先
trim(自己写个简易去空格函数,或用find_first_not_of/find_last_not_of) - 检查行是否为空或以
#开头(注释),跳过它们 - 用
find('=')找分隔符,别硬拆空格——log_path = /var/log/app.log里空格是路径一部分
std::map<:string std::string></:string> 存配置最省事,但要注意类型转换
键值都存成 std::string 最灵活,读写逻辑统一。但真正用的时候得转类型:端口号要 std::stoi,开关要判断是否等于 "true" 或 "1",浮点数用 std::stod。
容易踩的坑:std::stoi 遇到非法字符(比如 "port = abc")会抛 std::invalid_argument;没检查转换后是否溢出;布尔值只认 "true" 不认 "yes" 或空值。
立即学习“C++免费学习笔记(深入)”;
- 所有数值转换必须包在
try/catch里,或先用std::from_chars(C++17)做无异常校验 - 布尔配置建议约定统一值:
"on"/"off"或"1"/"0",避免自然语言歧义 - 不要把
std::map直接当全局变量暴露——封装成类,提供get_int("port", 8080)这样带默认值的接口
写配置时用 std::ofstream 清空重写比追加更安全
简单配置文件通常不支持热更新,写入就是覆盖。用 std::ofstream("config.txt") 默认是截断写(trunc),比先 remove() 再新建更原子——万一删了文件但写失败,就真丢了。
性能影响很小,但兼容性要注意:Windows 下路径含中文时,std::ofstream 默认用本地编码(如 GBK),而你代码里字符串是 UTF-8,会导致乱码。Linux/macOS 一般没问题。
- 写入前确保目录存在,
std::filesystem::create_directories(C++17)可帮忙 - 写完调
os.flush()并检查os.good(),别只靠析构自动关闭 - 避免在多线程里同时读写同一文件——没锁,必然错乱
配置项名大小写敏感,但用户常忽略这点
代码里用 config["Port"] 和 config["port"] 是两个键。而用户编辑 txt 时根本不会注意大小写,尤其 Windows 上文件系统不区分大小写,更强化了这种错觉。
真实场景中,80% 的“配置不生效”问题,其实是键名拼错或大小写不一致。别指望用户看文档记清大小写。
- 读取时统一转小写存 key(
std::transform(key.begin(), key.end(), key.begin(), ::tolower)) - 写配置时不主动改用户写的大小写,但读取接口一律按小写查——
get("PORT")和get("port")返回一样 - 如果必须保留原始大小写(比如导出给其他工具用),那就额外维护一个映射表,但普通内部配置没必要
配置文件看着简单,但空行、注释、空格、大小写、编码、异常输入,哪一环松动都会让程序静默失效。越想省事,越得把边界情况写死。










