C++ 配置文件類的封裝
阿新 • • 發佈:2018-08-14
ont fin 整型 em1 alloc unsigned swd 浮點 之前
有時開發項目,需要對數據庫等配置放到程序對外面作為配置文件,配置文件對讀取
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, §1, §2, &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;
C++ 配置文件類的封裝