标签:
1.概述
在大型软件系统中,为了监测软件运行状况及排查软件故障,一般都会要求软件程序在运行的过程中产生日志文件。在日志文件中存放程序流程中的一些重要信息,
包括:变量名称及其值、消息结构定义、函数返回值及其执行情况、脚本执行及调用情况等。通过阅读日志文件,我们能够较快地跟踪程序流程,并发现程序问题。
因此,熟练掌握日志系统的编写方法并快速地阅读日志文件,是对一个软件开发工程师的基本要求。
本文详细地介绍了Linux下一个简单的日志系统的设计方法,并给出了其C代码实现。本文为相关开发项目Linux下软件日志系统的编写提供了有益的参考。
2.日志系统的框架结构
一个完整的日志系统包括三大部分:配置文件、软件程序和日志文件,它们之间的关系如图1所示。
图1 一个完整的日志系统的框架结构
从图1可以看出,软件程序处于主导地位,它会从配置文件中读取相关的配置信息(这些配置信息用于控制每条日志信息的生成样式),经过处理之后将相关信息输出到日志文件中。
3.生成日志文件的程序流程
基于日志系统的框架结构,生成日志文件的程序流程如图2所示。
图2 生成日志文件的程序流程
在实际的软件程序中,为了在程序的不同地方打印不同的日志,要将生成日志的代码封装为函数,作为API供程序调用。
如果软件没有成功生成日志,那么就不要让其继续执行后续流程,而是要查找问题的原因,直到日志生成正常为止。
4.日志文件命名及日志信息格式
对于日志文件的命名,不同的软件开发项目有不同的规定。一般说来,日志文件都是以log作为后缀,如本文中的日志文件命名为:WriteLog.log。
对于每条日志信息的格式,对于不同的软件来说,也会有所不同。在本文中,日志信息的格式有以下两种(具体使用哪一种通过配置项决定):
第一种:[日志生成时间][文件名][函数名][代码行][日志等级]日志具体信息
第二种:[日志生成时间][日志等级]日志具体信息
5.配置文件说明
本文中使用的配置文件为Config.ini,它包括了两部分信息,如下所示:
[EMPLOYEEINFO]
;the name of employee
EmployeeName=
;the age of employee
EmployeeAge=
[LOG]
;LogLevel, 0-Fatal 1-Error 2-Warn 3-Info 4-Trace 5-Debug 6-All
LogLevel=
;If output position info(filename/functionname/linenum), 1-Yes 0-No
LogPosition=
;Log dir
LogDir=
其中,“EMPLOYEEINFO”段是指员工信息,包含员工姓名和员工年龄两个配置项。程序会将员工姓名和员工年龄读入,并输出到日志文件中。
“LOG”段是指日志信息,包含日志等级、日志代码位置标识和输出日志文件的目录三个配置项。对于“LogLevel”配置项,只有代码中日志等级不低于
配置值的日志信息才会被输出到日志文件中(例如,LogLevel=4,那么只有Fatal、Error、Warn、Info和Trace等级的日志会被
输出到日志文件中)。“LogPosition”配置项的值用于控制是否在日志文件中显示“文件名/函数名/代码行数”信息,1则显示,0则不显示。
“LogDir”配置项的值表示生成的日志文件存放的目录。
6.重要程序流程
(1) 从配置文件中读取各个配置项的值
该操作的流程如图3所示,具体请参见《Linux下配置文件读取操作流程及其C代码实现》(http://blog.csdn.net/zhouzhaoxiong1227/article/details/45563263)一文。
图3 配置文件读取操作程序流程
(2) 向日志文件中写入日志信息
该操作的流程如图4所示。
图4 向日志文件中写入日志信息程序流程
该流程的具体代码请参考本文附录中的完整程序代码中的WriteLogFile函数。
7.程序测试设计及文件上传
为了测试本日志系统的功能是否正确,在main函数中设计了以下三类日志信息:
第一类:打印程序的版本号及编译时间。
第二类:打印Fatal、Error、Warn、Info、Trace、Debug、All这七个等级的日志各一条。
第三类:调用GetEmployeeInfo函数打印读取到的员工姓名和年龄。
将本程序“WriteLog.c”上传到Linux的“/home/zhou/zhouzx/test”目录下,并在该目录下建立“etc”和“log”目录,将配置文件“Config.ini”上传到“etc”下。文件及目录布局如图5所示。
图5 文件及目录布局
8.代码编译及运行
在Linux下使用“gcc -g -o WriteLog WriteLog.c”命令对程序进行编译,生成“WriteLog”文件。
下面来运行程序。
(1) 将配置文件中的各个配置项的值设置如下:
[EMPLOYEEINFO]
;the name of employee
EmployeeName=wang
;the age of employee
EmployeeAge=25
[LOG]
;LogLevel, 0-Fatal 1-Error 2-Warn 3-Info 4-Trace 5-Debug 6-All
LogLevel=5
;If output position info(filename/linenum), 1-Yes 0-No
LogPosition=1
;Log dir
LogDir=/home/zhou/zhouzx/test/log
则生成的日志文件“WriteLog.log”的内容为:
[2015.05.22 11:12:29.402][WriteLog.c][main][0077][INFO]Version [1.0], Build time[May 22 2015 11:11:51].
[2015.05.22 11:12:29.402][WriteLog.c][main][0081][FATAL]The Fatal log info!
[2015.05.22 11:12:29.402][WriteLog.c][main][0085][ERROR]The Error log info!
[2015.05.22 11:12:29.403][WriteLog.c][main][0089][WARN]The Warn log info!
[2015.05.22 11:12:29.403][WriteLog.c][main][0093][INFO]The Info log info!
[2015.05.22 11:12:29.403][WriteLog.c][main][0097][TRACE]The Trace log info!
[2015.05.22 11:12:29.403][WriteLog.c][main][0101][DEBUG]The Debug log info!
[2015.05.22 11:12:29.403][WriteLog.c][GetEmployeeInfo][0144][INFO]EmployeeName is wang, EmployeeAge is 25
对照配置文件和日志文件,我们可以看到,“LogLevel”设置的是为5,因此只有日志等级不低于5的日志被输出到了日志文件中;“LogPosition”设置的是为1,因此在日志文件中显示了“文件名/函数名/代码行数”的信息。
(2) 将配置文件中的各个配置项的值设置如下:
[EMPLOYEEINFO]
;the name of employee
EmployeeName=Li
;the age of employee
EmployeeAge=28
[LOG]
;LogLevel, 0-Fatal 1-Error 2-Warn 3-Info 4-Trace 5-Debug 6-All
LogLevel=4
;If output position info(filename/functionname/linenum), 1-Yes 0-No
LogPosition=0
;Log dir
LogDir=/home/zhou/zhouzx/test/log
则生成的日志文件“WriteLog.log”的内容为:
[2015.05.22 11:16:53.104][INFO]Version [1.0], Build time[May 22 2015 11:11:51].
[2015.05.22 11:16:53.104][FATAL]The Fatal log info!
[2015.05.22 11:16:53.104][ERROR]The Error log info!
[2015.05.22 11:16:53.104][WARN]The Warn log info!
[2015.05.22 11:16:53.104][INFO]The Info log info!
[2015.05.22 11:16:53.104][TRACE]The Trace log info!
[2015.05.22 11:16:53.104][INFO]EmployeeName is Li, EmployeeAge is 28
对照配置文件和日志文件,我们可以看到,“LogLevel”设置的是为4,因此只有日志等级不低于4的日志被输出到了日志文件中;“LogPosition”设置的是为0,因此在日志文件中不显示“文件名/函数名/代码行数”的信息。
为了验证本日志系统功能的正常与否,要对程序进行多组测试,
9.总结
本文对Linux下一个简单的日志系统的设计方法进行了详细的介绍(其C代码实现请见附录),代码中的写日志相关函数可作为API供其它需要进行类似操作的程序调用。在使用本日志系统的过程中,有以下注意事项:
第一,配置文件中“LOG”段只包括了日志等级、日志代码位置标识和输出日志文件的目录三个配置项。在实际的软件开发项目中,还会有更多的配置参数,像存
放的日志文件的最大个数、每个日志文件的大小阈值、每个已写入完成的日志文件的命名等。可以在本程序的基础上进一步扩展来实现复杂的日志功能。
第二,本文中对日志信息的写入采用的是直接在日志文件后面追加的方式,因此每次测试之前,要在“log”目录下删除上一次产生的“WriteLog.log”文件,否则新的日志信息会写入旧的日志文件中。
第三,由于写日志函数WriteLogFile的入参较多,每次调用的时候编写代码较为繁琐,因此使用一个宏WRITELOGFILE来代替,且只需要带上日志等级和日志消息两个参数即可,其它的如代码文件名、函数名和代码行数直接使用系统自定义的宏即可。
附录:完整的程序代码
/**********************************************************************
* 版权所有 (C)2015, Zhou Zhaoxiong。
*
* 文件名称:WriteLog.c
* 文件标识:无
* 内容摘要:演示日志信息的打印方法
* 其它说明:无
* 当前版本:V1.0
* 作 者:Zhou Zhaoxiong
* 完成日期:20150522
*
**********************************************************************/
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
// 重定义数据类型
typedef signed int INT32;
typedef unsigned int UINT32;
typedef unsigned char UINT8;
// 函数宏定义
#define WRITELOGFILE(level, msg) WriteLogFile(__FILE__, __FUNCTION__, __LINE__, level, msg)
// 全局变量
UINT32 g_iLogLevel = 0; // 日志等级
UINT32 g_iLogPosition = 0; // 日志位置
UINT8 g_szLogFile[100] = {0}; // 带路径的日志文件名
// 日志级别定义
#define LOG_FATAL 0 // 严重错误
#define LOG_ERROR 1 // 一般错误
#define LOG_WARN 2 // 警告
#define LOG_INFO 3 // 一般信息
#define LOG_TRACE 4 // 跟踪信息
#define LOG_DEBUG 5 // 调试信息
#define LOG_ALL 6 // 所有信息
// 员工信息结构体定义
typedef struct
{
UINT8 szEmployeeName[128]; // 员工姓名
INT32 iEmployeeAge; // 员工年龄
} T_EmployeeInfo;
// 函数声明
void WriteLogFile(UINT8 *pszFileName, UINT8 *pszFunctionName, UINT32 iCodeLine, UINT32 iLogLevel, UINT8 *pszContent);
UINT8 *LogLevel(UINT32 iLogLevel);
void GetTime(UINT8 *pszTimeStr);
void GetConfigValue();
void GetStringContentValue(FILE *fp, UINT8 *pszSectionName, UINT8 *pszKeyName, UINT8 *pszOutput, UINT32 iOutputLen);
void GetConfigFileStringValue(UINT8 *pszSectionName, UINT8 *pszKeyName, UINT8 *pDefaultVal, UINT8 *pszOutput, UINT32 iOutputLen, UINT8 *pszConfigFileName);
INT32 GetConfigFileIntValue(UINT8 *pszSectionName, UINT8 *pszKeyName, UINT32 iDefaultVal, UINT8 *pszConfigFileName);
void GetEmployeeInfo();
INT32 main();
/**********************************************************************
* 功能描述:主函数
* 输入参数:无
* 输出参数:无
* 返 回 值:无
* 其它说明:无
* 修改日期 版本号 修改人 修改内容
* -------------------------------------------------------------------
* 20150522 V1.0 Zhou Zhaoxiong 创建
***********************************************************************/
INT32 main()
{
UINT8 szLogContent[1024] = {0};
// 获取配置文件中各个配置项的值
GetConfigValue();
// 先打印版本相关信息
snprintf(szLogContent, sizeof(szLogContent)-1, "Version [1.0], Build time[%s %s].", __DATE__, __TIME__);
WRITELOGFILE(LOG_INFO, szLogContent);
// 打印第一条日志
snprintf(szLogContent, sizeof(szLogContent)-1, "The Fatal log info!");
WRITELOGFILE(LOG_FATAL, szLogContent);
// 打印第二条日志
snprintf(szLogContent, sizeof(szLogContent)-1, "The Error log info!");
WRITELOGFILE(LOG_ERROR, szLogContent);
// 打印第三条日志
snprintf(szLogContent, sizeof(szLogContent)-1, "The Warn log info!");
WRITELOGFILE(LOG_WARN, szLogContent);
// 打印第四条日志
snprintf(szLogContent, sizeof(szLogContent)-1, "The Info log info!");
WRITELOGFILE(LOG_INFO, szLogContent);
// 打印第五条日志
snprintf(szLogContent, sizeof(szLogContent)-1, "The Trace log info!");
WRITELOGFILE(LOG_TRACE, szLogContent);
// 打印第六条日志
snprintf(szLogContent, sizeof(szLogContent)-1, "The Debug log info!");
WRITELOGFILE(LOG_DEBUG, szLogContent);
// 打印第七条日志
snprintf(szLogContent, sizeof(szLogContent)-1, "The All log info!");
WRITELOGFILE(LOG_ALL, szLogContent);
GetEmployeeInfo(); // 获取并打印员工信息
return 0;
}
/**********************************************************************
* 功能描述: 获取并打印员工信息
* 输入参数: 无
* 输出参数: 无
* 返 回 值: 无
* 其它说明: 无
* 修改日期 版本号 修改人 修改内容
* -------------------------------------------------------------------
* 20150522 V1.0 Zhou Zhaoxiong 创建
********************************************************************/
void GetEmployeeInfo()
{
UINT8 szLogContent[1024] = {0};
T_EmployeeInfo tEmployeeInfo = {0};
// 获取并打印员工信息
// 获取员工姓名
GetConfigFileStringValue("EMPLOYEEINFO", "EmployeeName", "", tEmployeeInfo.szEmployeeName, sizeof(tEmployeeInfo.szEmployeeName), "Config.ini");
// 获取员工年龄
tEmployeeInfo.iEmployeeAge = GetConfigFileIntValue("EMPLOYEEINFO", "EmployeeAge", 0, "Config.ini");
if (tEmployeeInfo.iEmployeeAge == -1) // 判断获取到的年龄是否正确
{
snprintf(szLogContent, sizeof(szLogContent)-1, "GetEmployeeInfo: Get EmployeeAge failed!");
WRITELOGFILE(LOG_ERROR, szLogContent);
return;
}
// 打印读取到的员工姓名和年龄
snprintf(szLogContent, sizeof(szLogContent)-1, "EmployeeName is %s, EmployeeAge is %d", tEmployeeInfo.szEmployeeName, tEmployeeInfo.iEmployeeAge);
WRITELOGFILE(LOG_INFO, szLogContent);
}
/**********************************************************************
* 功能描述: 将内容写到日志文件中
* 输入参数: pszFileName-代码文件名
pszFunctionName-代码所在函数名
iCodeLine-代码行
iLogLevel-日志等级
pszContent-每条日志的具体内容
* 输出参数: 无
* 返 回 值: 无
* 其它说明: 无
* 修改日期 版本号 修改人 修改内容
* -------------------------------------------------------------------
* 20150522 V1.0 Zhou Zhaoxiong 创建
********************************************************************/
void WriteLogFile(UINT8 *pszFileName, UINT8 *pszFunctionName, UINT32 iCodeLine, UINT32 iLogLevel, UINT8 *pszContent)
{
FILE *fp = NULL;
UINT8 szLogContent[2048] = {0};
UINT8 szTimeStr[128] = {0};
if (pszFileName == NULL || pszContent == NULL)
{
return;
}
// 过滤日志等级
if (iLogLevel > g_iLogLevel)
{
return;
}
fp = fopen(g_szLogFile, "at+"); // 打开文件, 每次写入的时候在后面追加
if (fp == NULL)
{
return;
}
// 写入日志时间
GetTime(szTimeStr);
fputs(szTimeStr, fp);
// 写入日志内容
if (g_iLogPosition == 1) // 在日志信息中显示"文件名/函数名/代码行数"信息
{
snprintf(szLogContent, sizeof(szLogContent)-1, "[%s][%s][%04d][%s]%s\n", pszFileName, pszFunctionName, iCodeLine, LogLevel(iLogLevel), pszContent);
}
else // 不用在日志信息中显示"文件名/代码行数"信息
{
snprintf(szLogContent, sizeof(szLogContent)-1, "[%s]%s\n", LogLevel(iLogLevel), pszContent);
}
fputs(szLogContent, fp);
fflush(fp); // 刷新文件
fclose(fp); // 关闭文件
fp = NULL; // 将文件指针置为空
return;
}
/**********************************************************************
* 功能描述: 获取对应的日志等级
* 输入参数: iLogLevel-日志等级
* 输出参数: 无
* 返 回 值: 日志等级信息字符串
* 其它说明: 无
* 修改日期 版本号 修改人 修改内容
* -------------------------------------------------------------------
* 20150522 V1.0 Zhou Zhaoxiong 创建
********************************************************************/
UINT8 *LogLevel(UINT32 iLogLevel)
{
switch (iLogLevel)
{
case LOG_FATAL:
{
return "FATAL";
}
case LOG_ERROR:
{
return "ERROR";
}
case LOG_WARN :
{
return "WARN";
}
case LOG_INFO :
{
return "INFO";
}
case LOG_TRACE:
{
return "TRACE";
}
case LOG_DEBUG:
{
return "DEBUG";
}
case LOG_ALL:
{
return "ALL";
}
default:
{
return "OTHER";
}
}
}
/**********************************************************************
* 功能描述: 获取时间串
* 输入参数: pszTimeStr-时间串
* 输出参数: pszTimeStr-时间串
* 返 回 值: 无
* 其它说明: 时间串样式: YYYY.MM.DD HH:MIN:SS.Usec
* 修改日期 版本号 修改人 修改内容
* -------------------------------------------------------------------
* 20150522 V1.0 Zhou Zhaoxiong 创建
********************************************************************/
void GetTime(UINT8 *pszTimeStr)
{
struct tm tSysTime = {0};
struct timeval tTimeVal = {0};
time_t tCurrentTime = {0};
UINT8 szUsec[20] = {0}; // 微秒
UINT8 szMsec[20] = {0}; // 毫秒
if (pszTimeStr == NULL)
{
return;
}
tCurrentTime = time(NULL);
localtime_r(&tCurrentTime, &tSysTime); // localtime_r是线程安全的
gettimeofday(&tTimeVal, NULL);
sprintf(szUsec, "%06d", tTimeVal.tv_usec); // 获取微秒
strncpy(szMsec, szUsec, 3); // 微秒的前3位为毫秒(1毫秒=1000微秒)
sprintf(pszTimeStr, "[%04d.%02d.%02d %02d:%02d:%02d.%3.3s]",
tSysTime.tm_year+1900, tSysTime.tm_mon+1, tSysTime.tm_mday,
tSysTime.tm_hour, tSysTime.tm_min, tSysTime.tm_sec, szMsec);
}
/**********************************************************************
* 功能描述: 获取配置文件完整路径(包含文件名)
* 输入参数: pszConfigFileName-配置文件名
pszWholePath-配置文件完整路径(包含文件名)
* 输出参数: 无
* 返 回 值: 无
* 其它说明: 无
* 修改日期 版本号 修改人 修改内容
* ------------------------------------------------------------------
* 20150522 V1.0 Zhou Zhaoxiong 创建
********************************************************************/
void GetCompletePath(UINT8 *pszConfigFileName, UINT8 *pszWholePath)
{
UINT8 *pszHomePath = NULL;
UINT8 szWholePath[256] = {0};
// 先对输入参数进行异常判断
if (pszConfigFileName == NULL || pszWholePath == NULL)
{
return;
}
pszHomePath = (UINT8 *)getenv("HOME"); // 获取当前用户所在的路径
if (pszHomePath == NULL)
{
return;
}
// 拼装配置文件路径
snprintf(szWholePath, sizeof(szWholePath)-1, "%s/zhouzx/test/etc/%s", pszHomePath, pszConfigFileName);
strncpy(pszWholePath, szWholePath, strlen(szWholePath));
}
/**********************************************************************
* 功能描述: 获取日志配置项的值
* 输入参数: 无
* 输出参数: 无
* 返 回 值: 无
* 其它说明: 无
* 修改日期 版本号 修改人 修改内容
* -------------------------------------------------------------------
* 20150522 V1.0 Zhou Zhaoxiong 创建
********************************************************************/
void GetConfigValue()
{
UINT8 szLogDir[256] = {0};
// 日志等级
g_iLogLevel = GetConfigFileIntValue("LOG", "LogLevel", 5, "Config.ini");
// 日志位置
g_iLogPosition = GetConfigFileIntValue("LOG", "LogPosition", 0, "Config.ini");
// 日志文件存放目录
GetConfigFileStringValue("LOG", "LogDir", "", szLogDir, sizeof(szLogDir), "Config.ini");
snprintf(g_szLogFile, sizeof(g_szLogFile)-1, "%s/WriteLog.log", szLogDir);
}
/**********************************************************************
* 功能描述: 获取具体的字符串值
* 输入参数: fp-配置文件指针
pszSectionName-段名, 如: GENERAL
pszKeyName-配置项名, 如: EmployeeName
iOutputLen-输出缓存长度
* 输出参数: pszOutput-输出缓存
* 返 回 值: 无
* 其它说明: 无
* 修改日期 版本号 修改人 修改内容
* ------------------------------------------------------------------
* 20150522 V1.0 Zhou Zhaoxiong 创建
********************************************************************/
void GetStringContentValue(FILE *fp, UINT8 *pszSectionName, UINT8 *pszKeyName, UINT8 *pszOutput, UINT32 iOutputLen)
{
UINT8 szSectionName[100] = {0};
UINT8 szKeyName[100] = {0};
UINT8 szContentLine[256] = {0};
UINT8 szContentLineBak[256] = {0};
UINT32 iContentLineLen = 0;
UINT32 iPositionFlag = 0;
// 先对输入参数进行异常判断
if (fp == NULL || pszSectionName == NULL || pszKeyName == NULL || pszOutput == NULL)
{
printf("GetStringContentValue: input parameter(s) is NULL!\n");
return;
}
sprintf(szSectionName, "[%s]", pszSectionName);
strcpy(szKeyName, pszKeyName);
while (feof(fp) == 0)
{
memset(szContentLine, 0x00, sizeof(szContentLine));
fgets(szContentLine, sizeof(szContentLine), fp); // 获取段名
// 判断是否是注释行(以;开头的行就是注释行)或以其他特殊字符开头的行
if (szContentLine[0] == ‘;‘ || szContentLine[0] == ‘\r‘ || szContentLine[0] == ‘\n‘ || szContentLine[0] == ‘\0‘)
{
continue;
}
// 匹配段名
if (strncasecmp(szSectionName, szContentLine, strlen(szSectionName)) == 0)
{
while (feof(fp) == 0)
{
memset(szContentLine, 0x00, sizeof(szContentLine));
memset(szContentLineBak, 0x00, sizeof(szContentLineBak));
fgets(szContentLine, sizeof(szContentLine), fp); // 获取字段值
// 判断是否是注释行(以;开头的行就是注释行)
if (szContentLine[0] == ‘;‘)
{
continue;
}
memcpy(szContentLineBak, szContentLine, strlen(szContentLine));
// 匹配配置项名
if (strncasecmp(szKeyName, szContentLineBak, strlen(szKeyName)) == 0)
{
iContentLineLen = strlen(szContentLine);
for (iPositionFlag = strlen(szKeyName); iPositionFlag <= iContentLineLen; iPositionFlag ++)
{
if (szContentLine[iPositionFlag] == ‘ ‘)
{
continue;
}
if (szContentLine[iPositionFlag] == ‘=‘)
{
break;
}
iPositionFlag = iContentLineLen + 1;
break;
}
iPositionFlag = iPositionFlag + 1; // 跳过=的位置
if (iPositionFlag > iContentLineLen)
{
continue;
}
memset(szContentLine, 0x00, sizeof(szContentLine));
strcpy(szContentLine, szContentLineBak + iPositionFlag);
// 去掉内容中的无关字符
for (iPositionFlag = 0; iPositionFlag < strlen(szContentLine); iPositionFlag ++)
{
if (szContentLine[iPositionFlag] == ‘\r‘ || szContentLine[iPositionFlag] == ‘\n‘ || szContentLine[iPositionFlag] == ‘\0‘)
{
szContentLine[iPositionFlag] = ‘\0‘;
break;
}
}
// 将配置项内容拷贝到输出缓存中
strncpy(pszOutput, szContentLine, iOutputLen-1);
break;
}
else if (szContentLine[0] == ‘[‘)
{
break;
}
}
break;
}
}
}
/**********************************************************************
* 功能描述: 从配置文件中获取字符串
* 输入参数: pszSectionName-段名, 如: GENERAL
pszKeyName-配置项名, 如: EmployeeName
pDefaultVal-默认值
iOutputLen-输出缓存长度
pszConfigFileName-配置文件名
* 输出参数: pszOutput-输出缓存
* 返 回 值: 无
* 其它说明: 无
* 修改日期 版本号 修改人 修改内容
* ------------------------------------------------------------------
* 20150522 V1.0 Zhou Zhaoxiong 创建
********************************************************************/
void GetConfigFileStringValue(UINT8 *pszSectionName, UINT8 *pszKeyName, UINT8 *pDefaultVal, UINT8 *pszOutput, UINT32 iOutputLen, UINT8 *pszConfigFileName)
{
FILE *fp = NULL;
UINT8 szWholePath[256] = {0};
// 先对输入参数进行异常判断
if (pszSectionName == NULL || pszKeyName == NULL || pszOutput == NULL || pszConfigFileName == NULL)
{
printf("GetConfigFileStringValue: input parameter(s) is NULL!\n");
return;
}
// 获取默认值
if (pDefaultVal == NULL)
{
strcpy(pszOutput, "");
}
else
{
strcpy(pszOutput, pDefaultVal);
}
// 打开配置文件
GetCompletePath(pszConfigFileName, szWholePath);
fp = fopen(szWholePath, "r");
if (fp == NULL)
{
printf("GetConfigFileStringValue: open %s failed!\n", szWholePath);
return;
}
// 调用函数用于获取具体配置项的值
GetStringContentValue(fp, pszSectionName, pszKeyName, pszOutput, iOutputLen);
// 关闭文件
fclose(fp);
fp = NULL;
}
/**********************************************************************
* 功能描述: 从配置文件中获取整型变量
* 输入参数: pszSectionName-段名, 如: GENERAL
pszKeyName-配置项名, 如: EmployeeName
iDefaultVal-默认值
pszConfigFileName-配置文件名
* 输出参数: 无
* 返 回 值: iGetValue-获取到的整数值 -1-获取失败
* 其它说明: 无
* 修改日期 版本号 修改人 修改内容
* ------------------------------------------------------------------
* 20150522 V1.0 Zhou Zhaoxiong 创建
********************************************************************/
INT32 GetConfigFileIntValue(UINT8 *pszSectionName, UINT8 *pszKeyName, UINT32 iDefaultVal, UINT8 *pszConfigFileName)
{
UINT8 szGetValue[512] = {0};
INT32 iGetValue = 0;
// 先对输入参数进行异常判断
if (pszSectionName == NULL || pszKeyName == NULL || pszConfigFileName == NULL)
{
printf("GetConfigFileIntValue: input parameter(s) is NULL!\n");
return -1;
}
GetConfigFileStringValue(pszSectionName, pszKeyName, NULL, szGetValue, 512-1, pszConfigFileName); // 先将获取的值存放在字符型缓存中
if (szGetValue[0] == ‘\0‘ || szGetValue[0] == ‘;‘) // 如果是结束符或分号, 则使用默认值
{
iGetValue = iDefaultVal;
}
else
{
iGetValue = atoi(szGetValue);
}
return iGetValue;
}
标签:
原文地址:http://www.cnblogs.com/timdes/p/4790466.html