本章节开始配置文件的读写功能
1. 配置文件格式
对于我们自己开发的软件,可以自行规定格式,然后实现读写功能即可;在本工程中规定如下格式:
- #、; 开头为注释
- 忽略开头的 ‘\t’,‘\n’ 和空格字符
- [] 内容为节点标记
- 忽略空行
- ‘=’ 区分左右两侧配置项和内容
在 bin 目录下新建一个 nginx_sim.conf 文件,内容暂时只需要配置与log相关的配置项
# 注释行
# 每个有效配置项用 = 处理,= 前不超过40字符,= 后不超过400字符
# 以 [ 开头表示组信息,也等价于注释行
Log = logs/error2.log
LogLevel = 5
2. 实现配置文件内容载入
新建一个 CConfig 类,专门用于对配置文件的读取;在 include 目录新建 ngx_conf.h 文件,在此文件声明类
class CConfig
{
private:
CConfig();
static CConfig* m_instance;
public:
~CConfig();
//单例模式。线程不安全【如果需要线程安全,则要加锁;本工程不会有多线程竞争,因此无关紧要】
static CConfig* GetInstance()
{
if(nullptr == m_instance)
{
m_instance = new CConfig();
static CFreeInstance freeInstance;
}
return m_instance;
}
//用于释放对象
class CFreeInstance
{
public:
~CFreeInstance()
{
if(CConfig::m_instance)
{
delete CConfig::m_instance;
CConfig::m_instance = nullptr;
}
}
};
//对外的接口
bool LoadConfig(const char* pConfigName);
std::string GetString(const char* pItemName);
int GetIntDefault(const char* pItemName,const int def);
private:
std::map<std::string,std::string>m_configList;
};
对类中方法的实现放在 src/ngx_conf.cxx
//静态成员初始化
CConfig* CConfig::m_instance = nullptr;
CConfig::CConfig()
{
}
CConfig::~CConfig()
{
}
bool CConfig::LoadConfig(const char* pConfigName)
{
FILE *fp;
fp = fopen(pConfigName,"r");
if(nullptr == fp)
{
return false;
}
char lineBuf[501];
while(!feof(fp))
{
if(nullptr == fgets(lineBuf,500,fp))
{
continue;
}
if(0 == *lineBuf || ' ' == *lineBuf || '#' == *lineBuf || ';' == *lineBuf || '\t' == *lineBuf || '\n' == *lineBuf)
{
continue;
}
loop:
auto size = strlen(lineBuf);
if(size > 0)
{
//抛掉末尾的换行,回车和空格
if(10 == lineBuf[size-1] || 13 == lineBuf[size-1] || 32 == lineBuf[size-1])
{
lineBuf[size-1] = 0;
goto loop;
}
}
if(0 == *lineBuf || '[' == *lineBuf)
{
continue;
}
//开始读取配置内容
char *pTmp = strchr(lineBuf,'=');
if(pTmp)
{
CConfItem pConfigItem;
memset(&pConfigItem,0,sizeof(CConfItem));
strncpy(pConfigItem.ItemName,lineBuf,(int)(pTmp - lineBuf));
strcpy(pConfigItem.ItemContent,pTmp + 1);
//去除首尾空格
Rtrim(pConfigItem.ItemName);
Ltrim(pConfigItem.ItemName);
Rtrim(pConfigItem.ItemContent);
Ltrim(pConfigItem.ItemContent);
m_configList[pConfigItem.ItemName] = pConfigItem.ItemContent;
}
}
fclose(fp);
return true;
}
std::string CConfig::GetString(const char* pItemName)
{
return m_configList[pItemName];
}
int CConfig::GetIntDefault(const char* pItemName,const int def)
{
auto iter = m_configList.find(std::string(pItemName));
if(iter != m_configList.end())
{
return atoi(iter->second.c_str());
}
return def;
}
3. log 配置载入初始化
现在可以通过 CConfig 类载入 log 的配置进行初始化工作了,修改 ngx_log_init 函数
void ngx_log_init()
{
u_char *plogname = NULL;
//从配置文件中读取和日志相关的配置信息
CConfig *p_config = CConfig::GetInstance();
std::string strPath = p_config->GetString("Log");
plogname = (u_char *)strPath.c_str();
if(strPath.empty())
{
//没读到,就要给个缺省的路径文件名了
plogname = (u_char *) NGX_ERROR_LOG_PATH; //"logs/error.log" ,logs目录需要提前建立出来
}
ngx_log.log_level = p_config->GetIntDefault("LogLevel",NGX_LOG_NOTICE);//缺省日志等级为6【注意】 ,如果读失败,就给缺省日志等级
//只写打开|追加到末尾|文件不存在则创建【这个需要跟第三参数指定文件访问权限】
//mode = 0644:文件访问权限, 6: 110 , 4: 100:
ngx_log.fd = open((const char *)plogname,O_WRONLY|O_APPEND|O_CREAT,0644);
if (ngx_log.fd == -1) //如果有错误,则直接定位到 标准错误上去
{
ngx_log_stderr(errno,"[alert] could not open error log file: open() \"%s\" failed", plogname);
ngx_log.fd = STDERR_FILENO; //直接定位到标准错误去了
}
return;
}
4. 编译、运行、测试
至此,我们已经可以从配置文件中读入log 的配置了;在程序启动时需要先载入配置文件,如下
int main(int argc, char* const* argv)
{
ngx_pid = getpid();
//加载配置文件内容
if(false == CConfig::GetInstance()->LoadConfig("nginx_sim.conf"))
{
//日志初始化(创建/打开日志文件)
ngx_log_init();
ngx_log_stderr(0,"配置文件[%s]载入失败,退出!","nginx_sim.conf");
//找不到文件
goto lblexit;
}
//日志初始化(创建/打开日志文件)
ngx_log_init();
ngx_log_stderr(0, "从配置文件中读到的 log 目录:%s",(CConfig::GetInstance()->GetString("Log")).c_str());
ngx_log_stderr(0, "从配置文件中读到的 log 等级:%d",CConfig::GetInstance()->GetIntDefault("LogLevel",NGX_LOG_NOTICE));
lblexit:
ngx_log_stderr(0,"程序退出!");
//该释放的资源要释放掉
freereSource(); //一系列的main返回前的释放动作函数
return 0;
}
编译运行查看结果

在bin/ogs目录下可以看出到成成了error2.log文件,并且log目录与等级和我们在配置文件中的配置是一致的;
5. 结语
至此,我们的工程最基础的功能已经搭建完毕了,拥有了log记录的功能和配置的能力。
接下来,我们将进入进程相关的话题。
Note: 到此的内容可以独立将代码抽取出来运动到其他项目,需要工程源码请评论留言
本文介绍了一个简单的配置文件读写功能实现方法,并通过一个CConfig类演示了如何从配置文件中读取日志相关配置进行初始化。
2071

被折叠的 条评论
为什么被折叠?



