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=);
// 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 - ; while ((p2 >= s) && isspace(*p2))
p2 --;
*(p2 + ) = '\0'; p1 = s;
while (*p1 && isspace(*p1))
p1 ++;
if (s != p1)
memmove(s, p1, p2 - p1 + );
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 = ;
cntCR = cntLF = ;
isQuot1 = isQuot2 = ;
cont1 = *rem1 = ;
content[] = ;
for (i = , p = buf; i < buflen; i ++, p ++)
{
if (*p == ) {
p ++;
break;
}
//2个CR或LF,行结束
if (cntCR == || cntLF == ) {
p --; //回溯1
break;
}
//CR或LF各1个之后任意字符,行结束
if (cntCR + cntLF >= ) {
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 = - isQuot1;
break;
case '\"':
if (!isQuot1)
isQuot2 = - isQuot2;
break;
case ';':
case '#':
if (isQuot1 || isQuot2)
break;
if (*rem1 == NULL)
*rem1 = p - cntblank;
break;
default:
if (isspace((unsigned char)*p)) {
cntblank ++;
} else {
cntblank = ;
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] = ; if (content[] == '[' && content[i - ] == ']')
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 = ;
char found = ; if (gBuffer == NULL) {
return ;
} while (gBuflen - uselen > ) {
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) - ] = ; //去尾部]
StrStrip(content + ); //去首尾空格
if (StriCmp(content + , section) == ) {
found = ;
*sect1 = p;
*sect2 = rem1;
*cont1 = nextline;
}
empty = nextline;
} else
if (LINE_VALUE == type) {
if (!found && section == NULL) {
found = ;
*sect1 = p;
*sect2 = p;
*cont1 = p;
}
empty = nextline;
}
} if (!found) return ; *cont2 = empty;
*nextsect = nextline;
return ;
} //从一行取键、值
//输入:内容串(将被改写)
//输出:键串、值串
void GetKeyValue(char *content, char **key, char **value)
{
char *p; p = strchr(content, '=');
*p = ;
StrStrip(content);
StrStrip(p + );
*key = content;
*value = p + ;
} //释放ini文件所占资源
void ConfigManager:: ConfigFileFree()
{
if (gBuffer != NULL) {
free(gBuffer);
gBuffer = ;
gBuflen = ;
}
} //加载ini文件至内存
int ConfigManager::ConfigFileLoad(const char *filename)
{
FILE *file;
int len; //iniFileFree();
if (strlen(filename) >= sizeof(gFilename))
return ;
strcpy(gFilename, filename); file = fopen(gFilename, "ab+");
if (file == NULL)
return ; fseek(file, , SEEK_END);
len = ftell(file);
gBuffer =(char *) malloc(len);
if (gBuffer == NULL) {
fclose(file);
return ;
} fseek(file, , SEEK_SET);
len = fread(gBuffer, , len, file);
fclose(file);
gBuflen = len;
return ;
} //读取值原始串
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 = ;
char found = ;
int len; if (gBuffer == NULL || key == NULL) {
if (value != NULL)
value[] = ;
return ;
} while (gBuflen - uselen > ) {
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) - ] = ; //去尾部]
StrStrip(content + ); //去首尾空格
if (StriCmp(content + , section) == ) {
found = ;
}
} else
if (LINE_VALUE == type) {
if (!found && section == NULL) {
found = ;
}
if (!found)
continue;
GetKeyValue(content, &key0, &value0);
if (StriCmp(key0, key) == ) {
len = strlen(value0);
if (len == ) break; //空值视为无效
if (value != NULL) {
len = fmin(len, maxlen - );
strncpy(value, value0, len);
value[len] = ;
}
// printf("value = %s\n",value);
return ;
}
}
} //未发现键值取缺省
if (value != NULL) {
if (defvalue != NULL) {
len = fmin(strlen(defvalue), maxlen - );
strncpy(value, defvalue, len);
value[len] = ;
SetString(section, key, defvalue);
} else {
value[] = ;
}
}
return ;
} //获取字符串,不带引号
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[] == '\'' && value[len - ] == '\'') {
value[len - ] = ;
memmove(value, value + , len - );
} else
if (value[] == '\"' && value[len - ] == '\"') {
value[len - ] = ;
memmove(value, value + , len - );
}
return ret;
} //获取整数值
int ConfigManager::GetInt(const char *section, const char *key, int defvalue)
{
char valstr[]; if (GetValue(section, key, valstr, sizeof(valstr), NULL))
return (int)strtol(valstr, NULL, );
SetInt(section, key,defvalue,);
return defvalue;
} //获取浮点数
double ConfigManager::GetDouble(const char *section, const char *key, double defvalue)
{
char valstr[]; 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 ;
} if (FindSection(section, §1, §2, &cont1, &cont2, &nextsect) == )
{
//未找到节
//value无效则返回
if (value == NULL)
return ;
//在文件尾部添加
file = fopen(gFilename, "ab");
if (file == NULL)
return ;
fprintf(file, "\r\n[%s]\r\n%s=%s;\r\n", section, key, value);
fclose(file);
ConfigFileLoad(gFilename);
return ;
} //找到节,则节内查找key
p = cont1;
len = (int)(cont2 - cont1);
while (len > ) {
type = GetLine(p, len, content, &rem1, &rem2, &nextline);
if (LINE_VALUE == type) {
GetKeyValue(content, &key0, &value0);
if (StriCmp(key0, key) == ) {
//找到key
file = fopen(gFilename, "wb");
if (file == NULL)
return ;
len = (int)(p - gBuffer);
fwrite(gBuffer, , 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, , gBuflen - len, file); //写入key所在行含注释之后部分
fclose(file);
ConfigFileLoad(gFilename);
return ;
}
} len -= (int)(nextline - p);
p = nextline;
} //未找到key //value无效则返回
if (value == NULL)
return ; //在文件尾部添加
file = fopen(gFilename, "wb");
if (file == NULL)
return ;
len = (int)(cont2 - gBuffer);
fwrite(gBuffer, , len, file); //写入key之前部分
fprintf(file, "%s=%s;\r\n", key, value);
fwrite(gBuffer + len, , gBuflen - len, file); //写入key之后部分
fclose(file);
ConfigFileLoad(gFilename);
return ;
} //设置整数值:base取值10、16、8,分别表示10、16、8进制,缺省为10进制
int ConfigManager::SetInt(const char *section, const char *key, int value, int base)
{
char valstr[]; switch (base) {
case :
sprintf(valstr, "0x%x", value);
return SetString(section, key, valstr);
case :
sprintf(valstr, "0%o", value);
return SetString(section, key, valstr);
default: //
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" ,);
//整型数字的获取
}
配置文件
[general]
cityid=1;
dbhost=127.0.0.1;
port=3306;
user=root;
passwd=root;
C++ 配置文件类的封装的更多相关文章
- C++ Config 配置文件类
C++ Config 配置文件类 本文Config类的序列化和反序列化使用的jsoncpp, 因为jsoncpp提供的方法很简单易阅读.配置文件的格式自然也是json. 1 { 2 "ima ...
- 配置文件类 Properties
Properties(配置文件类): 主要用于生产配置文件与读取配置文件的信息. Properties属于集合类,继承于Hashtable. Properties要注意的细节: 1. 如果配置文 ...
- iOS开发--QQ音乐练习,旋转动画的实现,音乐工具类的封装,定时器的使用技巧,SliderBar的事件处理
一.旋转动画的实现 二.音乐工具类的封装 -- 返回所有歌曲,返回当前播放歌曲,设置当前播放歌曲,返回下一首歌曲,返回上一首歌曲方法的实现 头文件 .m文件 #import "ChaosMu ...
- Java—类的封装、继承与多态
一.类和对象 1.类 类是数据以及对数据的一组操作的封装体. 类声明的格式: 类声明 { 成员变量的声明: 成员方法的声明及实现: } 1.1 声明类 [修饰符] class 类<泛型> ...
- 第三篇 :微信公众平台开发实战Java版之请求消息,响应消息以及事件消息类的封装
微信服务器和第三方服务器之间究竟是通过什么方式进行对话的? 下面,我们先看下图: 其实我们可以简单的理解: (1)首先,用户向微信服务器发送消息: (2)微信服务器接收到用户的消息处理之后,通过开发者 ...
- 025医疗项目-模块二:药品目录的导入导出-HSSF导入类的封装
上一篇文章提过,HSSF的用户模式会导致读取海量数据时很慢,所以我们采用的是事件驱动模式.这个模式类似于xml的sax解析.需要实现一个接口,HSSFListener接口. 原理:根据excel底层存 ...
- 022医疗项目-模块二:药品目录的导入导出-对XSSF导出excel类进行封装
资源全部来源于传智播客. 好的架构师写的程序,就算给刚入门的新手看,新手一看就知道怎么去用.所以我们要对XSSF导出excel类进行封装.这是架构师的工作,但我们也要知道. 我们写一个封装类: 这个类 ...
- 黑马程序员——JAVA基础之简述 类的封装
------- android培训.java培训.期待与您交流! ---------- 类的封装(Encapsulation) 封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式. 封装优 ...
- 【面试题001-补充】C++ MyString类的封装
[面试题001-补充]C++ MyString类的封装 一,C++ MyString类的封装 String.h: 123456789101112131415161718192021222324252 ...
随机推荐
- C-static,auto,register,volatile
static 一:静态,意思就是呆在一个地方,不想动,大概就是编译期间就确定地址了.首先了解下C中的进程内存布局: 1)正文段(.text)——CPU执行的机器指令部分:一个程序只有一个副本:只读,防 ...
- vue实战记录(二)- vue实现购物车功能之创建vue实例
vue实战,一步步实现vue购物车功能的过程记录,课程与素材来自慕课网,自己搭建了express本地服务器来请求数据 作者:狐狸家的鱼 本文链接:vue实战-实现购物车功能(二) GitHub:sue ...
- app升级注意事项version
1.每次升级生成apk前,修改versionName: 位置: 2.修改数据库表中对应version字段与之对应: 3.出现waiting for debugger,要重启手机: 5.解析包错误,是a ...
- MySQL查看SQL语句执行效率
Explain命令在解决数据库性能上是第一推荐使用命令,大部分的性能问题可以通过此命令来简单的解决,Explain可以用来查看 SQL 语句的执行效 果,可以帮助选择更好的索引和优化查询语句,写出更好 ...
- Fiddler--QuickExec
QuickExec在Fiddler中提供了比较快捷的功能服务. 在QuickExec输入框中输入命令,能快速地得到想要的结果. 快捷键:打开Fiddler后,按“Alt+q”,可将光标定位到Quick ...
- jQuery使用(十二):工具方法之type()之类型判断
type()的使用 类型判断方法之is...() 实现原理可以参考我的另一篇js源码剖析博客: 类型和原生函数及类型转换(二:终结js类型判断) $.type( undefined ) === &qu ...
- 还在用Json完成Ajax,改用Beetl吧
原文链接:https://blog.csdn.net/xiandafu/article/details/44216905 作者:Beetl作者,闲大赋 浏览器通过AJAX,服务器返回json数据,无刷 ...
- 网站设置ico图标
1.用设计的png图片去在线图标网站上生成一个16*16大小的图标,命名favcon.ico放置到网站根目录下如:http://www.faviconico.org/favicon2.添加代码 < ...
- auto类型说明符
auto让编译器通过出初始值来推算变量的类型,显然,auto定义的变量必须有初始值: //由val1和val2相加的结果可以推断出item的类型 auto item = val1 + val2;//i ...
- 调试 - Chrome调试
调试 - Chrome调试 打开开发人员工具 Ctrl+Shift+i可以打开开发人员工具. 功能面板 NetWork功能面板 在当前页面打开调试工具,刷新页面后点击NetWork可以查看当前页面的H ...