C++ 配置文件類的封裝


有時開發項目,需要對數據庫等配置放到程序對外面作為配置文件,配置文件對讀取

ConfigManager.h

/*
 * ConfigManager.h
 *
 *  Created on: 2018年7月28日
 *      Author: oftenlin
 */

#ifndef CONFIGMANAGER_H_
#define CONFIGMANAGER_H_
#define SIZE_FILENAME 50


class ConfigManager{
public:
    ConfigManager(const char *filename){ConfigFileLoad(filename);};
    ~ConfigManager(){ConfigFileFree();};
    //加載ini文件至內存

    char gFilename[SIZE_FILENAME];
    char *gBuffer;
    int gBuflen;
    int ConfigFileLoad(const char *filename);
    //釋放ini文件所占資源
    void ConfigFileFree();
    int FindSection(const char *section, char **sect1, char **sect2, char **cont1, char **cont2, char **nextsect);
    //獲取字符串,不帶引號
    int GetString(const char *section, const char *key, char *value, int size, const char *defvalue);
    //獲取整數值
    int GetInt(const char *section, const char *key, int defvalue);
    //獲取浮點數
    double GetDouble(const char *section, const char *key, double defvalue);
    int GetValue(const char *section, const char *key, char *value, int maxlen, const char *defvalue);
    //設置字符串:若value為NULL,則刪除該key所在行,包括注釋
    int SetString(const char *section, const char *key, const char *value);
    //設置整數值:base取值10、16、8,分別表示10、16、8進制,缺省為10進制
    int SetInt(const char *section, const char *key, int value, int base=10);
//    int iniGetIP(const char *section, const char *key, BasicHashTable *hashtable, int size, const char *defvalue);
};


#endif /* CONFIGMANAGER_H_ */

ConfigManager.cpp

/*
 * ConfigManager.cpp
 * Created on: 2018年7月28日
 * Author: oftenlin
 */


#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "ConfigManager.h"

#define  SIZE_LINE  100

#define fmin(x, y)      (x <= y) ? x : y

typedef enum _ELineType_ {
    LINE_IDLE,      //未處理行
    LINE_ERROR,     //錯誤行
    LINE_EMPTY,     //空白行或注釋行
    LINE_SECTION,   //節定義行
    LINE_VALUE      //值定義行
} ELineType ;


//去除串首尾空格,原串被改寫
 char *StrStrip(char *s)
{
    size_t size;
    char *p1, *p2;


    size = strlen(s);
    if (!size)
        return s;


    p2 = s + size - 1;


    while ((p2 >= s) && isspace(*p2))
        p2 --;
    *(p2 + 1) = '\0';


    p1 = s;
    while (*p1 && isspace(*p1))
        p1 ++;
    if (s != p1)
        memmove(s, p1, p2 - p1 + 2);
    return s;
}


//不區分大小寫比較字符串
 int StriCmp(const char *s1, const char *s2)
{
    int ch1, ch2;
    do
    {
        ch1 = (unsigned char)*(s1++);
        if ((ch1 >= 'A') && (ch1 <= 'Z'))
            ch1 += 0x20;


        ch2 = (unsigned char)*(s2++);
        if ((ch2 >= 'A') && (ch2 <= 'Z'))
            ch2 += 0x20;
    } while ( ch1 && (ch1 == ch2) );
    return(ch1 - ch2);
}

//取一行
//輸入:數據區(指針及長度)
//輸出:行類型、有效內容串(去首尾空格)、注釋首、注釋尾、下一行首(行尾與下一行首間為換行符)
//      有效內容位置為[buf, rem1)
 int GetLine(char *buf, int buflen, char *content, char **rem1, char **rem2, char **nextline)
{
    char *cont1, *cont2;
    int cntblank, cntCR, cntLF;     //連續空格、換行符數量
    char isQuot1, isQuot2;          //引號
    int i;
    char *p;

    //首先斷行斷注釋,支持如下換行符:\r、\n、\r\n、\n\r
    cntblank = 0;
    cntCR = cntLF = 0;
    isQuot1 = isQuot2 = 0;
    cont1 = *rem1 = 0;
    content[0] = 0;
    for (i = 0, p = buf; i < buflen; i ++, p ++)
    {
        if (*p == 0) {
            p ++;
            break;
        }
        //2個CR或LF,行結束
        if (cntCR == 2 || cntLF == 2) {
            p --;   //回溯1
            break;
        }
        //CR或LF各1個之后任意字符,行結束
        if (cntCR + cntLF >= 2) {
            break;
        }
        //CR或LF之后出現其它字符,行結束
        if ((cntCR || cntLF) && *p != '\r' && *p != '\n')
            break;


        switch (*p) {
        case '\r':
            cntCR ++;
            break;
        case '\n':
            cntLF ++;
            break;
        case '\'':
            if (!isQuot2)
                isQuot1 = 1 - isQuot1;
            break;
        case '\"':
            if (!isQuot1)
                isQuot2 = 1 - isQuot2;
            break;
        case ';':
        case '#':
            if (isQuot1 || isQuot2)
                break;
            if (*rem1 == NULL)
                *rem1 = p - cntblank;
            break;
        default:
            if (isspace((unsigned char)*p)) {
                cntblank ++;
            } else {
                cntblank = 0;
                if ((*rem1 == NULL) && (cont1 == NULL))
                    cont1 = p;
            }
            break;
        }
    }


    *nextline = p;
    *rem2 = p - cntCR - cntLF;
    if (*rem1 == NULL)
        *rem1 = *rem2;
    cont2 = *rem1 - cntblank;


    if (cont1 == NULL) {
        cont1 = cont2;
        return LINE_EMPTY;
    }


    i = (int)(cont2 - cont1);
    if (i >= SIZE_LINE)
        return LINE_ERROR;


    //內容頭尾已無空格
    memcpy(content, cont1, i);
    content[i] = 0;


    if (content[0] == '[' && content[i - 1] == ']')
        return LINE_SECTION;
    if (strchr(content, '=') != NULL)
        return LINE_VALUE;

    return LINE_ERROR;
}

//取一節section
//輸入:節名稱
//輸出:成功與否、節名稱首、節名稱尾、節內容首、節內容尾(含換行)、下一節首(節尾與下一節首間為空行或注釋行)
 int ConfigManager::FindSection(const char *section, char **sect1, char **sect2, char **cont1, char **cont2, char **nextsect)
{
    int type;
    char content[SIZE_LINE];
    char *rem1, *rem2, *nextline;


    char *p;
    char *empty;
    int uselen = 0;
    char found = 0;

    if (gBuffer == NULL) {
        return 0;
    }

    while (gBuflen - uselen > 0) {
        p = gBuffer + uselen;
        type = GetLine(p, gBuflen - uselen, content, &rem1, &rem2, &nextline);
        uselen += (int)(nextline - p);


        if (LINE_SECTION == type) {
            if (found || section == NULL) break;        //發現另一section
            content[strlen(content) - 1] = 0;           //去尾部]
            StrStrip(content + 1);                      //去首尾空格
            if (StriCmp(content + 1, section) == 0) {
                found = 1;
                *sect1 = p;
                *sect2 = rem1;
                *cont1 = nextline;
            }
            empty = nextline;
        } else
        if (LINE_VALUE == type) {
            if (!found && section == NULL) {
                found = 1;
                *sect1 = p;
                *sect2 = p;
                *cont1 = p;
            }
            empty = nextline;
        }
    }

    if (!found) return 0;


    *cont2 = empty;
    *nextsect = nextline;
    return 1;
}

//從一行取鍵、值
//輸入:內容串(將被改寫)
//輸出:鍵串、值串
 void GetKeyValue(char *content, char **key, char **value)
{
    char *p;

    p = strchr(content, '=');
    *p = 0;
    StrStrip(content);
    StrStrip(p + 1);
    *key = content;
    *value = p + 1;
}

//釋放ini文件所占資源
void ConfigManager:: ConfigFileFree()
{
    if (gBuffer != NULL) {
        free(gBuffer);
        gBuffer = 0;
        gBuflen = 0;
    }
}

//加載ini文件至內存
int ConfigManager::ConfigFileLoad(const char *filename)
{
    FILE *file;
    int len;

    //iniFileFree();
    if (strlen(filename) >= sizeof(gFilename))
        return 0;
    strcpy(gFilename, filename);


    file = fopen(gFilename, "ab+");
    if (file == NULL)
        return 0;


    fseek(file, 0, SEEK_END);
    len = ftell(file);
    gBuffer =(char *) malloc(len);
    if (gBuffer == NULL) {
        fclose(file);
        return 0;
    }


    fseek(file, 0, SEEK_SET);
    len = fread(gBuffer, 1, len, file);
    fclose(file);
    gBuflen = len;
    return 1;
}

//讀取值原始串
 int ConfigManager::GetValue(const char *section, const char *key, char *value, int maxlen, const char *defvalue)
{
    int type;
    char content[SIZE_LINE];
    char *rem1, *rem2, *nextline;
    char *key0, *value0;


    char *p;
    int uselen = 0;
    char found = 0;
    int len;

    if (gBuffer == NULL || key == NULL) {
        if (value != NULL)
            value[0] = 0;
        return 0;
    }

    while (gBuflen - uselen > 0) {
        p = gBuffer + uselen;
        type = GetLine(p, gBuflen - uselen, content, &rem1, &rem2, &nextline);
        uselen += (int)(nextline - p);


        if (LINE_SECTION == type) {
            if (found || section == NULL) break;        //發現另一section
            content[strlen(content) - 1] = 0;           //去尾部]
            StrStrip(content + 1);                      //去首尾空格
            if (StriCmp(content + 1, section) == 0) {
                found = 1;
            }
        } else
        if (LINE_VALUE == type) {
            if (!found && section == NULL) {
                found = 1;
            }
            if (!found)
                continue;
            GetKeyValue(content, &key0, &value0);
            if (StriCmp(key0, key) == 0) {
                len = strlen(value0);
                if (len == 0) break;        //空值視為無效
                if (value != NULL) {
                    len = fmin(len, maxlen - 1);
                    strncpy(value, value0, len);
                    value[len] = 0;
                }
            //  printf("value = %s\n",value);
                return 1;
            }
        }
    }

    //未發現鍵值取缺省
    if (value != NULL) {
        if (defvalue != NULL) {
            len = fmin(strlen(defvalue), maxlen - 1);
            strncpy(value, defvalue, len);
            value[len] = 0;
            SetString(section, key, defvalue);
        } else {
            value[0] = 0;
        }
    }
    return 0;
}

//獲取字符串,不帶引號
int ConfigManager::GetString(const char *section, const char *key, char *value, int maxlen, const char *defvalue)
{
    int ret;
    int len;

    ret = GetValue(section, key, value, maxlen, defvalue);
    if (!ret)
        return ret;

    //去首尾空格
    len = strlen(value);
    if (value[0] == '\'' && value[len - 1] == '\'') {
        value[len - 1] = 0;
        memmove(value, value + 1, len - 1);
    } else
    if (value[0] == '\"' && value[len - 1] == '\"') {
        value[len - 1] = 0;
        memmove(value, value + 1, len - 1);
    }
    return ret;
}

//獲取整數值
int ConfigManager::GetInt(const char *section, const char *key, int defvalue)
{
    char valstr[64];


    if (GetValue(section, key, valstr, sizeof(valstr), NULL))
        return (int)strtol(valstr, NULL, 0);
    SetInt(section, key,defvalue,10);
    return defvalue;
}

//獲取浮點數
double ConfigManager::GetDouble(const char *section, const char *key, double defvalue)
{
    char valstr[64];

    if (GetValue(section, key, valstr, sizeof(valstr), NULL))
        return (int)atof(valstr);
    return defvalue;
}

//設置字符串:若value為NULL,則刪除該key所在行,包括注釋
int ConfigManager::SetString(const char *section, const char *key, const char *value)
{
    FILE *file;
    char *sect1, *sect2, *cont1, *cont2, *nextsect;
    char *p;
    int len, type;
    char content[SIZE_LINE];
    char *key0, *value0;
    char *rem1, *rem2, *nextline;

    if (gBuffer == NULL) {
        return 0;
    }


    if (FindSection(section, &sect1, &sect2, &cont1, &cont2, &nextsect) == 0)
    {
        //未找到節
        //value無效則返回
        if (value == NULL)
            return 0;
        //在文件尾部添加
        file = fopen(gFilename, "ab");
        if (file == NULL)
            return 0;
        fprintf(file, "\r\n[%s]\r\n%s=%s;\r\n", section, key, value);
        fclose(file);
        ConfigFileLoad(gFilename);
        return 1;
    }


    //找到節,則節內查找key
    p = cont1;
    len = (int)(cont2 - cont1);
    while (len > 0) {
        type = GetLine(p, len, content, &rem1, &rem2, &nextline);
        if (LINE_VALUE == type) {
            GetKeyValue(content, &key0, &value0);
            if (StriCmp(key0, key) == 0) {
                //找到key
                file = fopen(gFilename, "wb");
                if (file == NULL)
                    return 0;
                len = (int)(p - gBuffer);
                fwrite(gBuffer, 1, len, file);                  //寫入key之前部分
                if (value == NULL) {
                    //value無效,刪除
                    len = (int)(nextline - gBuffer);            //整行連同注釋一並刪除
                } else {
                    //value有效,改寫
                    fprintf(file, "%s=%s", key, value);
                    len = (int)(rem1 - gBuffer);                //保留尾部原注釋!
                }
                fwrite(gBuffer + len, 1, gBuflen - len, file);  //寫入key所在行含注釋之后部分
                fclose(file);
                ConfigFileLoad(gFilename);
                return 1;
            }
        }


        len -= (int)(nextline - p);
        p = nextline;
    }

    //未找到key

    //value無效則返回
    if (value == NULL)
        return 0;

    //在文件尾部添加
    file = fopen(gFilename, "wb");
    if (file == NULL)
        return 0;
    len = (int)(cont2 - gBuffer);
    fwrite(gBuffer, 1, len, file);                  //寫入key之前部分
    fprintf(file, "%s=%s;\r\n", key, value);
    fwrite(gBuffer + len, 1, gBuflen - len, file);  //寫入key之后部分
    fclose(file);
    ConfigFileLoad(gFilename);
    return 1;
}

//設置整數值:base取值10、16、8,分別表示10、16、8進制,缺省為10進制
int ConfigManager::SetInt(const char *section, const char *key, int value, int base)
{
    char valstr[64];

    switch (base) {
    case 16:
        sprintf(valstr, "0x%x", value);
        return SetString(section, key, valstr);
    case 8:
        sprintf(valstr, "0%o", value);
        return SetString(section, key, valstr);
    default:    //10
        sprintf(valstr, "%d", value);
        return SetString(section, key, valstr);
    }
}

讀取方法

#include "utils/ConfigManager.h"
int main() {
    ConfigManager *configManger=new 
    ConfigManager("config.ini");
    char *general_sect="general";
    int city = configManger->GetInt(general_sect,"cityid" ,1);
    //整型數字的獲取
  
}

配置文件

[general]
cityid=1;
dbhost=127.0.0.1;
port=3306;
user=root;
passwd=root;

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM