首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

STL 實作高效 INI 設定檔解析器

     編輯:關於VC++

前言

INI 檔案格式簡單易讀,廣泛用於應用程式設定儲存。本文展示如何運用 C++ STL (map, vector, string, algorithm) 快速建立一個輕量、標頭檔唯一的 INI 解析類別 IniFile,支援 Section/Key/Value 查詢、註解忽略、空白修剪。

INI 格式範例

# 註解行
[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; // "_____***_______"
};

核心實作細節

1. 讀檔與分行 (do_open)

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();
}

2. 解析函式物件 (analyzeini)

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));
    }
};

3. 讀取介面 (read)

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;
}

設計亮點總結

  • 標頭檔唯一:無需額外 .cpp,直接 #include "inifile.h" 即用。
  • STL 容器零管理:map 自動處理鍵值查找,vector 自動管理記憶體。
  • 函式物件 + for_each:解析邏輯封裝於 analyzeini,可攜帶 current_section 狀態,程式碼清晰。
  • Unicode/多位元組就緒:若專案啟用 Unicode,將 string 改為 wstring、ifstream 改 wifstream 即可遷移。

擴充建議

  • 支援 GetInt, GetBool, GetFloat 等型別轉換。
  • 提供 write / save 修改寫回功能。
  • 支援巢狀 Section 或陣列值語法。

完整 inifile.h 可直接下載使用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved