当前位置: 首页 > news >正文

C++轻量级配置管理器升级版

通过重构此前的INI轻量级配置管理器,新的配置库的核心设计目标是提供一种统一的接口来操作多种格式(INI, JSON, XML)的配置文件,同时保证类型安全线程安全。它通过抽象基类、继承和多态机制,将不同格式的解析细节隐藏起来,为上层应用提供了简洁一致的getset接口,同时支持更简洁的 [] 运算符,使操作更加简单明了。

🧱 一、整体架构概览

整个库的架构清晰,主要由以下几个核心类构成,它们之间的协作关系如下图所示:

聚合
被抛出
包含
1
*
递归包含 (树形结构)
1
*
ConfigException
+ConfigException(String& msg, int line)
«static»
ConfigErrorHandler
+logError(message, throwEx)
ConfigNode
-m_value: String
-m_config: map<String, ConfigNode>
...
+to() : T
+operator[](key)
+add(key, value)
+keys()
ConfigParser
#m_filePath: String
#m_config: map<String, ConfigNode>
...
+load(filePath)
+toString()
+get(section, key, defaultValue) : T
+set(section, key, value)
+sections()
IniParser
+load(filePath)
+toString()
-parseLine(line, currentSection, lineNumber)
JsonParser
+load(filePath)
+toString()
XmlParser
+load(filePath)
+toString()
ConfigManager
-m_mutex: mutex
-m_configParser: shared_ptr<ConfigParser>
...
+get(section, key, defaultValue) : T
+set(section, key, value)
+save(filePath)
+operator[](section)
  • ConfigException & ConfigErrorHandler:异常处理层
  • ConfigNode:配置数据结构的核心容器
  • ConfigParser:抽象解析器基类,定义通用接口
  • IniParser / JsonParser / XmlParser:具体格式解析器
  • ConfigManager:对外统一接口,封装线程安全与格式识别

⚡ 二、核心类详解

1️⃣ ConfigException & ConfigErrorHandler —— 错误处理机制

class ConfigException : public std::runtime_error
{
public:ConfigException(const String &msg, int line = -1): std::runtime_error(line < 0 ? msg : msg + " at line " + String(line)) {}
};
  • 继承自 std::runtime_error,便于集成标准异常处理机制。
  • 支持带行号的错误信息,便于调试。
class ConfigErrorHandler
{
public:static void logError(const String &message, bool throwEx = true){std::cerr << "Config Error: " << message << std::endl;if(throwEx) throw ConfigException(message);}
};
  • 静态工具类,统一错误输出格式。
  • 可选择是否抛出异常,提供灵活性(如日志记录后继续执行)。

2️⃣ ConfigNode —— 配置数据的核心容器

class ConfigNode
{
public:using ConfigConstIterator = std::map<String, ConfigNode>::const_iterator;ConfigNode() = default;ConfigNode(const String &value);ConfigNode(const ConfigNode &node); // 拷贝ConfigNode(ConfigNode&& other) noexcept; // 移动ConfigNode &operator[](const String &key); // 支持链式访问ConfigNode &operator=(const String &value); // 赋值重载// ... 其他赋值重载size_t erase(const String &key);ConfigNode &add(const String &key, const ConfigNode& value);template<typename T> T to() const; // 类型转换std::vector<String> keys() const;ConfigConstIterator find(const String &key) const;
private:std::map<String, ConfigNode> m_config; // 子节点String m_value; // 当前节点值(叶子)
};
  • 🔍 核心特性:

  • 树形结构: m_config 存储子节点,m_value 存储当前值,支持嵌套配置。

  • 链式访问: config[“server”][“port”] = “8080”。

  • 多种赋值方式: 支持 String、double、long、ConfigNode。

  • 移动语义: 提升性能,避免深拷贝开销。

  • 类型转换模板:

template<>
bool ConfigNode::to<bool>() const { ... } // 特化 bool 转换template<typename T>
inline T ConfigNode::to() const {return ::fromString<T>(m_value); // 依赖外部 fromString<T>
}

⚠️ 注意:依赖全局函数 fromString<T>toString,在String.hpp中实现,也可自行实现。

3️⃣ ConfigParser —— 抽象配置解析器

class ConfigParser
{
public:virtual bool load(const String &filePath) = 0;virtual String toString() = 0;virtual bool save(const String &filePath);virtual bool save();template<typename T> T get(...) const;template<typename T> void set(...);bool has(const String &section) const;void remove(const String &section, const String &key);ConfigNode &operator[](const String &section);protected:String m_filePath;std::map<String, ConfigNode> m_config; // 所有节
};

📌 关键方法:

  • get<T>() 模板:
template<typename T>
inline T ConfigParser::get(const String &section, const String &key, const T& defaultValue) const
{auto section_it = m_config.find(section);if(section_it != m_config.end()) {auto key_it = section_it->second.find(key);if(key_it != section_it->second.end()) {try {return ::fromString<T>(key_it->second.toString());} catch(...) {}}}return defaultValue; // 容错设计
}
  • 支持默认值,避免程序崩溃。

  • 内部 ·try-catch·,转换失败返回默认值,非异常驱动设计。

  • set<T>() 模板:

template<typename T>
inline void ConfigParser::set(const String &section, const String &key, const T& value)
{if(m_config.find(section) == m_config.end()) {m_config.insert(std::make_pair(section, ConfigNode()));}m_config[section][key] = ::toString(value); // 依赖 toString
}
  • 自动创建节(section),无需预先声明。
  • 依赖 ::toString(value),支持自定义类型。

4️⃣ IniParser —— INI 格式具体实现

class IniParser : public ConfigParser
{
public:bool load(const String &filePath) override;String toString() override;
private:void parseLine(const String &line, const String &currentSection, int lineNumber);
};

📄 INI 文件格式示例:

[Database]
host = localhost
port = 5432
ssl = true[Server]
port = 8080
debug = false

🔍 load() 解析流程:

  • 逐行读取
  • 跳过空行/注释(# 或 ;)
  • [Section] → 设置 currentSection
  • key = value → 调用 parseLine()
void IniParser::parseLine(const String &line, const String &currentSection, int lineNumber)
{size_t eqPos = line.find('=');if(eqPos != String::npos) {String key = trim(line.substr(0, eqPos));String value = trim(line.substr(eqPos + 1));if(!currentSection.empty()) {m_config[currentSection][key] = value;} else {throw ConfigException("No section for key '" + key + "'", lineNumber);}} else {throw ConfigException("Invalid line", lineNumber);}
}

📝 toString() 生成格式化输出:

String IniParser::toString()
{String result;for(const auto& section : sections()) {result += "[" + section + "]\n";for(const auto& key : keys(section)) {result += key + " = " + m_config[section][key].to<String>() + "\n";}result += "\n";}return result;
}

✅ 支持自动格式化、节间空行,提高可读性。

5️⃣ JsonParser / XmlParser (待实现)

实现文件解析接口 load 和文件格式化输出接口 toString

bool load(const String &filePath) { ... }
String toString() { ... }

🚀 扩展建议:可集成 nlohmann/json 或 pugixml 库实现完整功能。

6️⃣ ConfigManager —— 统一入口 & 线程安全网关

class ConfigManager
{
public:ConfigManager(const String &filePath);bool load(const String &filePath);template<typename T> bool set(...);template<typename T> T get(...) const;bool save();std::vector<String> sections();ConfigNode &operator[](const String &section);private:mutable std::mutex m_mutex;std::shared_ptr<ConfigParser> m_configParser;
};

🔄 自动格式识别:

bool ConfigManager::load(const String &filePath)
{String file_type = filePath.subAfter('.').lower();if(file_type == "json") m_configParser.reset(new JsonParser());else if(file_type == "xml") m_configParser.reset(new XmlParser());else m_configParser.reset(new IniParser()); // 默认INIreturn m_configParser->load(filePath);
}

📎链式访问

ConfigNode &operator[](const String &section);
  • 通过实现ConfigManager、ConfigParser、ConfigNode[] 的运算符实现了快捷方便的链式访问

🧪 三、使用示例

#include "src/ConfigManager.hpp"int main()
{ConfigManager config;// 1. 加载配置文件if(!config.load("app.conf")){std::cerr << "Failed to load config file." << std::endl;// 可以选择创建一个默认配置config.set("Database", "host", "localhost");config.set("Database", "port", 5432);config.set("Database", "username", "user");config.set("Database", "password", "pass");config.set("UI", "theme", "dark");config.set("UI", "language", "en");config.set("UI", "auto_save", true);config.save("app.conf"); // 保存默认配置std::cout << "Created default config file 'app.conf'." << std::endl;}// 2. 读取配置值String dbHost = config.get<String>("Database", "host", "default_host");int dbPort = config.get<int>("Database", "port", 3306); // 默认端口3306String theme = config.get<String>("UI", "theme", "light");bool autoSave = config.get<bool>("UI", "auto_save", false);std::cout << "Database Host: " << dbHost << std::endl;std::cout << "Database Port: " << dbPort << std::endl;std::cout << "UI Theme: " << theme << std::endl;std::cout << "Auto Save: " << (autoSave ? "Enabled" : "Disabled") << std::endl;// 3. 修改配置值config.set("Database", "host", "newhost.example.com");config.set("UI", "language", "zh");// 使用[]方式修改config["UI"]["theme"] = "light";// 4. 添加新的配置项config.set("Logging", "level", "DEBUG");config.set("Logging", "file", "app.log");// 使用[]方式添加配置项config["System"]["version"] = "1.0.0";// 5. 保存修改后的配置if(!config.save()){std::cerr << "Failed to save config file." << std::endl;}else{std::cout << "Config file saved successfully." << std::endl;}// 6. 检查存在性if(config.has("Logging")){std::cout << "Section 'Logging' exists." << std::endl;}if(config.has("UI", "language")){std::cout << "Key 'language' exists in section 'UI'." << std::endl;}// 7. 获取所有节和键std::cout << "\nAll Sections:" << std::endl;std::cout << config.toString();return 0;
}

运行结果:

运行结果
项目源码


文章转载自:

http://1HUEDoEg.nwqyq.cn
http://aB15gxMf.nwqyq.cn
http://2VWoCwwi.nwqyq.cn
http://n3RiqItE.nwqyq.cn
http://nPtN7D6n.nwqyq.cn
http://ptX4I70u.nwqyq.cn
http://CMdS99ak.nwqyq.cn
http://1gfzpwMq.nwqyq.cn
http://SXtEko5p.nwqyq.cn
http://e2VzGLEQ.nwqyq.cn
http://VrFmNtQN.nwqyq.cn
http://P6KbXcfG.nwqyq.cn
http://hrJ6XHbu.nwqyq.cn
http://u6ucly23.nwqyq.cn
http://j9UHhGjI.nwqyq.cn
http://DvCxKx5s.nwqyq.cn
http://okqp3Svn.nwqyq.cn
http://iOq4apdv.nwqyq.cn
http://UqkmjvMu.nwqyq.cn
http://izziBKs9.nwqyq.cn
http://RL1TCFVw.nwqyq.cn
http://2FugVwvK.nwqyq.cn
http://IOQn1YKc.nwqyq.cn
http://7OZ4ru0f.nwqyq.cn
http://KW2ApSed.nwqyq.cn
http://1Ur5fz0X.nwqyq.cn
http://bY53ytfp.nwqyq.cn
http://wEiP9qmV.nwqyq.cn
http://YQ10uAdI.nwqyq.cn
http://ebX8Lnwu.nwqyq.cn
http://www.dtcms.com/a/379502.html

相关文章:

  • WiFi CSI标准
  • 9、从水果店账本到AI大脑:矩阵运算如何驱动现代人工智能?零基础完全指南(Transformer数学原理)
  • 外部碎片和内部碎片
  • Product Hunt 每日热榜 | 2025-09-11
  • 【前沿技术拓展Trip Two】具身智能
  • LeetCode 1658. 将x减到0的最小操作数
  • 二十二、包管理与发布 (Cargo 进阶)
  • WAF如何为你的网站筑起智能防线?
  • 【Leetcode】高频SQL基础题--1327.列出指定时间段内所有的下单产品
  • 数据结构与算法:绪论和线性表
  • ToDesk企业版高效助力睿尔博汽车信息服务!
  • 基于RFID技术的宠物自动喂食器方案
  • Java 异常体系全解析
  • Linux 系统资源负载控制脚本:CPU 内存一键管理(后台常驻版)
  • rook-ceph登录报错Invalid credentials
  • 《RocketMQ核心架构与实战解析》
  • C语言---常量
  • 豆包・图像创作模型 Seedream 4.0 正式发布!
  • OCSP(Online Certificate Status Protocol,在线证书状态协议)
  • 深度学习(六):代价函数的意义
  • 【lite.ai.toolkit】【深度学习】【Ubuntu 20.04】C++ 轻量级AI模型工具箱的编译、安装、使用教程
  • 远程创意协作新方式:cpolar助力Drawnix跨地域团队协作
  • 深入理解 Linux 内核进程管理
  • 企业跨区域组网新解:SD-WAN技术打造安全稳定网络体系
  • 单身杯2 web
  • 《Learning Langchain》阅读笔记12-RAG(8):RAG的优化策略
  • daily notes[43]
  • LRU缓存详解:用C语言实现高效数据管理
  • 灵码产品演示:软件工程架构分析
  • 硬件电路-陀机