news 2026/5/1 5:02:44

C++:读ini文件(附带源码)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++:读ini文件(附带源码)

一、项目背景详细介绍

在上一节中,我们已经完成了使用 C++ 写 INI 文件的实现。但在真实的软件系统中,“写配置”只是第一步,“读配置”才是程序运行时最核心的能力

几乎所有非硬编码的程序,启动流程都会包含如下步骤:

  1. 启动程序

  2. 读取配置文件(INI / JSON / YAML 等)

  3. 解析配置参数

  4. 根据配置初始化系统

  5. 进入主业务逻辑

在轻量级应用、工具程序、跨平台项目、嵌入式系统中,INI 文件仍然是最常见、最稳定、最低依赖的配置方式之一

典型使用场景包括:

  • 服务器端口、IP、线程数配置

  • 数据库连接参数

  • 日志级别、日志路径

  • 功能开关(enable / disable)

  • 运行环境参数

因此,掌握“如何用 C++ 正确读取 INI 文件”是一项非常基础但极其重要的能力

本项目将从零开始,使用纯 C++ 标准库,实现一个完整、可扩展、工程级的 INI 文件读取示例,并系统讲解其设计与实现思路。


二、项目需求详细介绍

2.1 功能性需求

本项目需要实现以下核心功能:

  1. 打开并读取一个 INI 文件

  2. 解析文件中的Section(节)

  3. 解析每个 Section 下的Key = Value

  4. 忽略注释行与空行

  5. 将解析结果存储到内存结构中

  6. 支持通过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 文件由三种元素组成:

  1. 注释

    • ;#开头

  2. 节(Section)

    • [SectionName]

  3. 键值对

    • 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 字符串处理基础

解析过程中涉及:

  • 去除首尾空格

  • 判断注释行

  • 查找=位置

  • 截取字符串


四、实现思路详细介绍

整体实现流程如下:

  1. 打开 INI 文件

  2. 定义当前 Section 名称

  3. 逐行读取文件

  4. 对每一行进行预处理:

    • 去除首尾空白

    • 忽略空行和注释行

  5. 如果是 Section 行:

    • 更新当前 Section

  6. 如果是 Key=Value 行:

    • 解析 Key 和 Value

    • 存入 Map

  7. 提供接口函数获取配置值


五、完整实现代码

/******************************************************** * 文件名: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下。


九、扩展方向与性能优化

9.1 增加getInt / getBool / getDouble

9.2 支持配置热加载(文件变更检测)

9.3 保留注释并支持原地修改

9.4 与IniWriter合并为完整配置模块

9.5 使用unordered_map提升查询性能

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/1 5:00:03

如何用OpenCore Legacy Patcher让老旧Mac重获新生:2024系统指南

如何用OpenCore Legacy Patcher让老旧Mac重获新生&#xff1a;2024系统指南 【免费下载链接】OpenCore-Legacy-Patcher 体验与之前一样的macOS 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 当苹果官方停止对2012年及更早Mac设备的系统更…

作者头像 李华
网站建设 2026/4/26 6:32:37

零门槛跨系统体验:macOS虚拟机新手指南

零门槛跨系统体验&#xff1a;macOS虚拟机新手指南 【免费下载链接】OneClick-macOS-Simple-KVM Tools to set up a easy, quick macOS VM in QEMU, accelerated by KVM. Works on Linux AND Windows. 项目地址: https://gitcode.com/gh_mirrors/on/OneClick-macOS-Simple-KV…

作者头像 李华
网站建设 2026/4/30 2:58:44

轻松提取音频特征向量!Emotion2Vec+ Embedding功能详解

轻松提取音频特征向量&#xff01;Emotion2Vec Embedding功能详解 1. 引言&#xff1a;为什么我们需要音频特征向量&#xff1f; 你有没有想过&#xff0c;一段语音除了能听出“开心”还是“难过”&#xff0c;还能告诉我们更多&#xff1f;比如它的情绪强度、说话人的状态&a…

作者头像 李华
网站建设 2026/4/28 21:30:34

Qwen All-in-One镜像推荐:无需GPU的轻量AI服务部署教程

Qwen All-in-One镜像推荐&#xff1a;无需GPU的轻量AI服务部署教程 1. 为什么你需要一个“不用GPU也能跑”的AI服务&#xff1f; 你是不是也遇到过这些情况&#xff1f; 想在公司老旧的办公电脑上试个AI功能&#xff0c;结果卡在“CUDA out of memory”&#xff1b; 想给客户…

作者头像 李华
网站建设 2026/4/30 15:12:11

帧级 vs 整句级情感分析?科哥镜像两种模式使用场景解析

帧级 vs 整句级情感分析&#xff1f;科哥镜像两种模式使用场景解析 1. 为什么粒度选择决定分析质量&#xff1f; 你上传一段30秒的客服录音&#xff0c;系统返回一个“中性”标签——这真的准确吗&#xff1f; 还是说&#xff0c;前5秒客户语气平和&#xff0c;中间10秒突然提…

作者头像 李华
网站建设 2026/4/19 3:10:16

Llama3-8B游戏NPC对话设计:互动系统搭建详细步骤

Llama3-8B游戏NPC对话设计&#xff1a;互动系统搭建详细步骤 1. 为什么选Llama3-8B做游戏NPC&#xff1f; 你有没有想过&#xff0c;游戏里的NPC不再只会重复三句话&#xff1f;当玩家问“昨晚的月色真美&#xff0c;你觉得呢”&#xff0c;它能接一句带点诗意又符合角色性格…

作者头像 李华