INI 檔案格式簡單易讀,廣泛用於應用程式設定儲存。本文展示如何運用 C++ STL (map, vector, string, algorithm) 快速建立一個輕量、標頭檔唯一的 INI 解析類別 IniFile,支援 Section/Key/Value 查詢、註解忽略、空白修剪。
# 註解行
[path]
dictfile = /home/tmp/dict.dat
inputfile= /home/tmp/input.txt
[exe]
user= winter
passwd= 1234567
database= mydatabase
class IniFile
{
public:
IniFile() {}
~IniFile() {}
// 開啟並解析 INI 檔
bool open(const char* pinipath);
// 讀取值,找不到回傳空字串
std::string read(const char* psect, const char* pkey);
protected:
// 內部實作
bool do_open(const char* pinipath);
// 儲存結構: "section_____***_______key" -> "value"
typedef std::map> strMap;
strMap c_inimap;
static const char* const MIDDLESTRING; // "_____***_______"
};
bool IniFile::do_open(const char* pinipath)
{
std::ifstream fin(pinipath);
if (!fin.is_open()) return false;
std::vector lines;
std::string line;
while (std::getline(fin, line))
{
// 移除尾部空白/換行
while (!line.empty() && isspace(line.back())) line.pop_back();
lines.push_back(line);
}
if (lines.empty()) return false;
// 使用 for_each + 函式物件逐行解析
std::for_each(lines.begin(), lines.end(), analyzeini(c_inimap));
return !c_inimap.empty();
}
struct analyzeini
{
std::string current_section;
strMap* pmap;
analyzeini(strMap& m) : pmap(&m) {}
void operator()(const std::string& line)
{
// 1. 忽略空行與註解
if (line.empty() || line[0] == '#' || line[0] == '/') return;
// 2. 偵測 [section]
size_t lb = line.find('[');
size_t rb = line.rfind(']');
if (lb != std::string::npos && rb != std::string::npos && lb < rb)
{
current_section = line.substr(lb + 1, rb - lb - 1);
return;
}
// 3. 無 section 時略過
if (current_section.empty()) return;
// 4. 解析 key=value
size_t eq = line.find('=');
if (eq == std::string::npos) return;
std::string key = trim(line.substr(0, eq));
std::string value = trim(line.substr(eq + 1));
// 5. 移除 value 尾端註解 (# 或 //)
value = strip_trailing_comment(value);
// 6. 組合鍵值存入 map
std::string mapkey = current_section + MIDDLESTRING + key;
(*pmap)[mapkey] = value;
}
// 輔助函式:去首尾空白
static std::string trim(const std::string& s)
{
size_t first = s.find_first_not_of(" \t");
if (first == std::string::npos) return "";
size_t last = s.find_last_not_of(" \t");
return s.substr(first, last - first + 1);
}
// 輔助函式:移除尾端註解
static std::string strip_trailing_comment(const std::string& s)
{
static const char* patterns[] = {" #", "\t#", " //", "\t//"};
size_t pos = std::string::npos;
for (auto pat : patterns)
{
size_t p = s.find(pat);
if (p != std::string::npos && (pos == std::string::npos || p < pos))
pos = p;
}
return (pos == std::string::npos) ? s : trim(s.substr(0, pos));
}
};
std::string IniFile::read(const char* psect, const char* pkey)
{
std::string mapkey = psect;
mapkey += MIDDLESTRING;
mapkey += pkey;
strMap::iterator it = c_inimap.find(mapkey);
return (it == c_inimap.end()) ? "" : it->second;
}
#include
#include "inifile.h"
int main()
{
IniFile ini;
if (!ini.open("test.ini")) return -1;
std::string val = ini.read("exe", "user");
if (val.empty()) return -1;
std::cout << "value=" << val << std::endl; // 輸出: value=winter
return 0;
}
#include "inifile.h" 即用。map 自動處理鍵值查找,vector 自動管理記憶體。analyzeini,可攜帶 current_section 狀態,程式碼清晰。string 改為 wstring、ifstream 改 wifstream 即可遷移。GetInt, GetBool, GetFloat 等型別轉換。write / save 修改寫回功能。完整 inifile.h 可直接下載使用。