設計目標
- 支持
key = value 格式,# 開頭為註釋;
- 自動去除首尾空白;
- 模板方法
Read() 直接轉換為任意支持 >> 的類型;
- 提供默認值重載,避免異常拋出;
- 支持流式輸出
operator<< 便於調試。
核心類定義 (Config.h)
#pragma once
#include <string>, <map>, <iostream>, <fstream>, <sstream>
class Config {
std::string delimiter, comment;
std::map<std::string, std::string> contents;
using mapci = std::map<std::string, std::string>::const_iterator;
static void Trim(std::string& s);
template<class T> static std::string T_as_string(const T& t);
template<class T> static T string_as_T(const std::string& s);
// 特化 bool 與 string
public:
Config(std::string filename, std::string delim="=", std::string comm="#");
Config();
bool FileExist(std::string filename);
void ReadFile(std::string filename, std::string delim="=", std::string comm="#");
bool KeyExists(const std::string& key) const;
template<class T> T Read(const std::string& key) const; // 無默認值,鍵不存在拋 Key_not_found
template<class T> T Read(const std::string& key, const T& def) const; // 有默認值
template<class T> bool ReadInto(T& var, const std::string& key) const;
template<class T> bool ReadInto(T& var, const std::string& key, const T& def) const;
template<class T> void Add(const std::string& key, const T& value);
void Remove(const std::string& key);
std::string GetDelimiter() const { return delimiter; }
std::string GetComment() const { return comment; }
std::string SetDelimiter(const std::string& s);
std::string SetComment(const std::string& s);
friend std::ostream& operator<<(std::ostream&, const Config&);
friend std::istream& operator>>(std::istream&, Config&);
struct File_not_found { std::string filename; };
struct Key_not_found { std::string key; };
};
關鍵實現細節 (Config.cpp)
operator>> 逐行讀取,跳過註釋,支援多行值(下一行無分隔符且非空視為續行);
string_as_T<bool> 識別 false/F/no/n/0/none(不區分大小寫)為 false,其餘為 true;
Trim 使用 find_first_not_of / find_last_not_of 去除空白字符。
使用示例
// config.txt
ipAddress = 10.10.90.125
port = 3001
username = mark
password = 2d2df5a
// main.cpp
#include "Config.h"
int main() {
Config cfg("config.txt");
int port = cfg.Read("port", 0);
std::string ip = cfg.Read("ipAddress", "127.0.0.1");
std::string user = cfg.Read("username", "");
std::string pwd = cfg.Read("password", "");
std::cout << "port:" << port << "\nip:" << ip << "\nuser:" << user << "\npwd:" << pwd << '\n';
return 0;
}
擴展建議
- 支援 Section(
[section])分組;
- 增加
GetAllKeys() 遍歷接口;
- 線程安全封裝(讀寫鎖)。