一、项目背景详细介绍
在上一节中,我们已经完成了使用 C++ 写 INI 文件的实现。但在真实的软件系统中,“写配置”只是第一步,“读配置”才是程序运行时最核心的能力。
几乎所有非硬编码的程序,启动流程都会包含如下步骤:
启动程序
读取配置文件(INI / JSON / YAML 等)
解析配置参数
根据配置初始化系统
进入主业务逻辑
在轻量级应用、工具程序、跨平台项目、嵌入式系统中,INI 文件仍然是最常见、最稳定、最低依赖的配置方式之一。
典型使用场景包括:
服务器端口、IP、线程数配置
数据库连接参数
日志级别、日志路径
功能开关(enable / disable)
运行环境参数
因此,掌握“如何用 C++ 正确读取 INI 文件”是一项非常基础但极其重要的能力。
本项目将从零开始,使用纯 C++ 标准库,实现一个完整、可扩展、工程级的 INI 文件读取示例,并系统讲解其设计与实现思路。
二、项目需求详细介绍
2.1 功能性需求
本项目需要实现以下核心功能:
打开并读取一个 INI 文件
解析文件中的Section(节)
解析每个 Section 下的Key = Value
忽略注释行与空行
将解析结果存储到内存结构中
支持通过
Section + Key查询配置值
2.2 非功能性需求
为了满足教学与工程实践:
仅使用 C++ 标准库
代码结构清晰、注释完整
易于扩展为完整配置管理模块
兼容 Windows / Linux / macOS
对格式有一定容错能力(空格、空行)
2.3 支持的 INI 文件格式
; 示例配置文件 [Database] host = 127.0.0.1 port = 3306 user = root password = 123456 [Server] ip = 0.0.0.0 port = 8080
三、相关技术详细介绍
3.1 INI 文件的核心元素
INI 文件由三种元素组成:
注释
以
;或#开头
节(Section)
[SectionName]
键值对
key = value
3.2 C++ 按行读取文件
使用:
std::getline(inputFile, line);
优点:
自动处理不同平台换行符
适合文本解析
内存占用低
3.3 数据存储结构设计
为了便于查询,我们采用双层 Map 结构:
Section └── Key -> Value
对应 C++ 类型:
std::map<std::string, std::map<std::string, std::string>>
3.4 字符串处理基础
解析过程中涉及:
去除首尾空格
判断注释行
查找
=位置截取字符串
四、实现思路详细介绍
整体实现流程如下:
打开 INI 文件
定义当前 Section 名称
逐行读取文件
对每一行进行预处理:
去除首尾空白
忽略空行和注释行
如果是 Section 行:
更新当前 Section
如果是 Key=Value 行:
解析 Key 和 Value
存入 Map
提供接口函数获取配置值
五、完整实现代码
/******************************************************** * 文件名:read_ini.cpp * 功能:使用 C++ 读取并解析 INI 配置文件 * 说明: * 1. 支持 Section / Key / Value * 2. 忽略注释和空行 * 3. 使用 map 存储配置数据 ********************************************************/ #include <iostream> #include <fstream> #include <string> #include <map> /** * @brief 去除字符串首尾空白字符 * @param str 原始字符串 * @return 处理后的字符串 */ std::string trim(const std::string& str) { size_t first = str.find_first_not_of(" \t\r\n"); if (first == std::string::npos) { return ""; } size_t last = str.find_last_not_of(" \t\r\n"); return str.substr(first, last - first + 1); } /** * @brief INI 文件解析类 */ class IniReader { public: /** * @brief 加载并解析 INI 文件 * @param fileName INI 文件路径 * @return true 解析成功 * @return false 解析失败 */ bool load(const std::string& fileName) { std::ifstream ifs(fileName); if (!ifs.is_open()) { return false; } std::string line; std::string currentSection; // 按行读取 INI 文件 while (std::getline(ifs, line)) { // 去除首尾空白 line = trim(line); // 跳过空行 if (line.empty()) { continue; } // 跳过注释行 if (line[0] == ';' || line[0] == '#') { continue; } // Section 行 if (line.front() == '[' && line.back() == ']') { currentSection = trim(line.substr(1, line.size() - 2)); continue; } // Key=Value 行 size_t pos = line.find('='); if (pos == std::string::npos) { continue; } std::string key = trim(line.substr(0, pos)); std::string value = trim(line.substr(pos + 1)); // 存储到 map 中 data_[currentSection][key] = value; } ifs.close(); return true; } /** * @brief 获取配置值 * @param section Section 名称 * @param key Key 名称 * @param defaultValue 默认值 * @return 配置值或默认值 */ std::string get( const std::string& section, const std::string& key, const std::string& defaultValue = "") const { auto secIt = data_.find(section); if (secIt == data_.end()) { return defaultValue; } auto keyIt = secIt->second.find(key); if (keyIt == secIt->second.end()) { return defaultValue; } return keyIt->second; } private: // Section -> (Key -> Value) std::map<std::string, std::map<std::string, std::string>> data_; }; int main() { IniReader reader; if (!reader.load("config.ini")) { std::cerr << "读取 INI 文件失败!" << std::endl; return 1; } // 示例读取配置项 std::string dbHost = reader.get("Database", "host", "localhost"); std::string dbPort = reader.get("Database", "port", "3306"); std::string serverPort = reader.get("Server", "port", "8080"); std::cout << "Database Host: " << dbHost << std::endl; std::cout << "Database Port: " << dbPort << std::endl; std::cout << "Server Port: " << serverPort << std::endl; return 0; }六、代码详细解读(仅解读方法作用)
6.1trim方法
用于去除字符串首尾的空格、Tab、换行符
是解析 INI 文件时的基础工具函数
6.2IniReader::load
打开并逐行读取 INI 文件
忽略空行和注释
解析 Section 与 Key=Value
将结果存储到嵌套
map结构中
6.3IniReader::get
根据
Section + Key查询配置值如果不存在,返回默认值
避免程序因缺失配置而崩溃
6.4main函数
创建解析器对象
加载配置文件
读取并使用配置项
七、项目详细总结
通过本项目,你已经系统掌握:
INI 文件格式规范
C++ 文本文件解析流程
字符串处理技巧
配置数据结构设计思想
可扩展配置管理的基础架构
该实现方式简单、可靠、无第三方依赖,非常适合:
教学
工具程序
嵌入式系统
基础服务组件
八、项目常见问题及解答
Q1:是否支持中文 Key / Value?
支持。INI 是纯文本格式,与编码无关。
Q2:是否支持大小写不敏感?
当前实现区分大小写,可在trim后统一转小写扩展。
Q3:是否支持同名 Key?
后出现的 Key 会覆盖前一个值。
Q4:如果没有 Section 怎么办?
会存储在空字符串 Section下。