zoukankan      html  css  js  c++  java
  • Linux下一个简单的日志系统的设计及其C代码实现

    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=
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    其中,“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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    则生成的日志文件“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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    对照配置文件和日志文件,我们可以看到,“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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    则生成的日志文件“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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    对照配置文件和日志文件,我们可以看到,“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
    ", pszFileName, pszFunctionName, iCodeLine, LogLevel(iLogLevel), pszContent);
        }
        else    // 不用在日志信息中显示"文件名/代码行数"信息
        {
            snprintf(szLogContent, sizeof(szLogContent)-1, "[%s]%s
    ", 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!
    ");
            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] == '
    ' || szContentLine[0] == '
    ' || szContentLine[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] == '
    ' || szContentLine[iPositionFlag] == '
    ' || szContentLine[iPositionFlag] == '')
                            {
                                szContentLine[iPositionFlag] = '';
                                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!
    ");
            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!
    ", 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!
    ");
            return -1;
        }
    
        GetConfigFileStringValue(pszSectionName, pszKeyName, NULL, szGetValue, 512-1, pszConfigFileName);    // 先将获取的值存放在字符型缓存中
    
        if (szGetValue[0] == '' || szGetValue[0] == ';')    // 如果是结束符或分号, 则使用默认值
        {
            iGetValue = iDefaultVal;
        }
        else
        {
            iGetValue = atoi(szGetValue);
        }
    
        return iGetValue;
    }
    
  • 相关阅读:
    mysql优化
    查询优化
    MySql服务器逻辑架构
    存储过程和存储函数区别
    mysql表设计原则
    mysql事务
    操作系统内存管理
    mysql索引介绍
    InnoDB与Myisam的区别
    【SVN】关于钩子的一些使用
  • 原文地址:https://www.cnblogs.com/timssd/p/4790466.html
Copyright © 2011-2022 走看看