读取配置文件方式

 我们在程序编写中往往会遇到这样的情况,程序运行中我们会读取配置文件,从中读取我们程序需要的各种参数与配置信息,我一般采用读取配置文件和使用Berkeley db的方式,这两种方式的移植性都较好,当然前者更好,但是后者也有它的好处,它可以很好的处理配置信息的读取等等,但是它需要bdb库的支持,虽然库很小,但对我们来讲,还是麻烦,所以我们一般还是采用读取配置文件的方式,而读取配置文件的方式又有很多种,本篇就讲第一种方式,也是我最常用的一种方式,单纯的用C库函数来实现.

.示例

这里我们还是以usb_modeswitch的代码为例子进行讲解,首先看一下它的配置文件:usb_modeswitch.conf,其中的格式如下部分所示:

[c-sharp]  view plain copy
  1. ########################################################  
  2. # Huawei E630  
  3. #  
  4. # There seem to be modem-only variants around - no storage,  
  5. # no switching  
  6. #  
  7. # Contributor: Joakim Wenrgren   
  8. ;DefaultVendor=  0x1033  
  9. ;DefaultProduct= 0x0035   
  10. ;TargetVendor=   0x12d1  
  11. ;TargetProduct=  0x1003   
  12. # choose one of these:  
  13. ;HuaweiMode=1  
  14. ;DetachStorageOnly=1   
  15. ########################################################  

.读取此配置文件的程序实现 

 

[cpp]  view plain copy
  1. /////////////////////////////////////////////////////////  
  2. //  
  3. /********************************************************** 
  4. //真正的配置文件解析函数,它的实现很简单,就不详细分析了,主要就是利用几个标准库函数就可以处理了, 
  5. //主要包括:fgets,strchr ,strcspn ,strrchr ,strspn , 
  6. // 
  7. // 
  8. **********************************************************/  
  9. /***************************************/  
  10. // the parameter parsing stuff  
  11. /***************************************/  
  12. char* ReadParseParam(const char* FileName, char *VariableName)  
  13. {  
  14.     static char Str[LINE_DIM];  
  15.     char *VarName, *Comment=NULL, *Equal=NULL;  
  16.     char *FirstQuote, *LastQuote, *P1, *P2;  
  17.     int Line=0, Len=0, Pos=0;  
  18.     FILE *file=fopen(FileName, "r");  
  19.       
  20.     if (file==NULL) {  
  21.         fprintf(stderr, "Error: Could not find file %s/n/n", FileName);  
  22.         exit(1);  
  23.     }  
  24.   
  25.     while (fgets(Str, LINE_DIM-1, file) != NULL) {  
  26.         Line++;  
  27.         Len=strlen(Str);  
  28.         if (Len==0) goto Next;  
  29.         if (Str[Len-1]=='/n' or Str[Len-1]=='/r') Str[--Len]='/0';  
  30.         Equal = strchr (Str, '=');          // search for equal sign  
  31.         Pos = strcspn (Str, ";#!");         // search for comment  
  32.         Comment = (Pos==Len) ? NULL : Str+Pos;  
  33.         if (Equal==NULL or ( Comment!=NULL and Comment<=Equal)) goto Next;   // Only comment  
  34.         *Equal++ = '/0';  
  35.         if (Comment!=NULL) *Comment='/0';  
  36.   
  37.         // String  
  38.         FirstQuote=strchr (Equal, '"');     // search for double quote char  
  39.         LastQuote=strrchr (Equal, '"');  
  40.         if (FirstQuote!=NULL) {  
  41.             if (LastQuote==NULL) {  
  42.                 fprintf(stderr, "Error reading parameter file %s line %d - Missing end quote./n", FileName, Line);  
  43.                 goto Next;  
  44.             }  
  45.             *FirstQuote=*LastQuote='/0';  
  46.             Equal=FirstQuote+1;  
  47.         }  
  48.           
  49.         // removes leading/trailing spaces  
  50.         Pos=strspn (Str, " /t");  
  51.         if (Pos==strlen(Str)) {  
  52.             fprintf(stderr, "Error reading parameter file %s line %d - Missing variable name./n", FileName, Line);  
  53.             goto Next;      // No function name  
  54.         }  
  55.         while ((P1=strrchr(Str, ' '))!=NULL or (P2=strrchr(Str, '/t'))!=NULL)  
  56.             if (P1!=NULL) *P1='/0';  
  57.             else if (P2!=NULL) *P2='/0';  
  58.         VarName=Str+Pos;  
  59.         //while (strspn(VarName, " /t")==strlen(VarName)) VarName++;  
  60.   
  61.         Pos=strspn (Equal, " /t");  
  62.         if (Pos==strlen(Equal)) {  
  63.             fprintf(stderr, "Error reading parameter file %s line %d - Missing value./n", FileName, Line);  
  64.             goto Next;      // No function name  
  65.         }  
  66.         Equal+=Pos;  
  67.   
  68.         if (strcmp(VarName, VariableName)==0) {     // Found it  
  69.             fclose(file);  
  70.             return Equal;  
  71.         }  
  72.         Next:;  
  73.     }  
  74.       
  75.     // not found  
  76. //  fprintf(stderr, "Error reading parameter file %s - Variable %s not found.",   
  77. //              FileName, VariableName);  
  78.     fclose(file);  
  79.     return NULL;  
  80. }  
  81.   
  82.   
  83. //  
  84. //  
  85. //  
  86. //*根据各种将要读取参数的类型,我们定义如下宏,用于各种不同的处理。*/  
  87. /********************************************************************* 
  88. 注意:对于函数的带参宏定义,没有使用过的人可能会有疑问,在带参宏定义中,形式参数不分配内存单元,因此不必作类型定义。而宏调用中的实参有具体的值。要用它们去代换形参,因此必须作类型说明。这是与函数中的情况不同的。在函数中,形参和实参是两个不同的量,各有自己的作用域,调用时要把实参值赋予形参,进行“值传递”。而在带参宏中,只是符号代换,不存在值传递的问题。 
  89.  
  90. ***********************************************************************/  
  91. //////////  
  92. //  
  93. //  
  94. extern char* ReadParseParam(const char* FileName, char *VariableName);  
  95.   
  96. extern char *TempPP;  
  97. //字符串参数  
  98. #define ParseParamString(ParamFileName, Str) /  
  99.     if ((TempPP=ReadParseParam((ParamFileName), #Str))!=NULL) /  
  100.         strcpy(Str, TempPP); else Str[0]='/0'  
  101. //整数参数        
  102. #define ParseParamInt(ParamFileName, Int) /  
  103.     if ((TempPP=ReadParseParam((ParamFileName), #Int))!=NULL) /  
  104.         Int=atoi(TempPP)  
  105. //16进制整数参数  
  106. #define ParseParamHex(ParamFileName, Int) /  
  107.     if ((TempPP=ReadParseParam((ParamFileName), #Int))!=NULL) /  
  108.         Int=strtol(TempPP, NULL, 16)  
  109. //浮点数参数  
  110. #define ParseParamFloat(ParamFileName, Flt) /  
  111.     if ((TempPP=ReadParseParam((ParamFileName), #Flt))!=NULL) /  
  112.         Flt=atof(TempPP)  
  113. //布尔型参数  
  114. #define ParseParamBool(ParamFileName, B) /  
  115.     if ((TempPP=ReadParseParam((ParamFileName), #B))!=NULL) /  
  116.         B=(toupper(TempPP[0])=='Y' || toupper(TempPP[0])=='T'|| TempPP[0]=='1'); else B=0  
  117.   
  118. //  
  119. //  
  120. //*************************************************************************  
  121. ////////////////////  
  122. 根据不同的参数类型和参数内容的性质(string,int,hex,bool?),调用不同的函数,实际上是调用同一函数只是进行不同的处理而以,由于这些处理很容易,故直接在宏定义定义成不同的函数了,使程序的条理更加清晰。  
  123. ***************************************************************************/  
  124. /////////////  
  125. void readConfigFile(const char *configFilename)  
  126. {  
  127.     if (verbose) printf("Reading config file: %s/n", configFilename);  
  128.     ParseParamHex(configFilename, TargetVendor);  
  129.     ParseParamHex(configFilename, TargetProduct);  
  130.     ParseParamString(configFilename, TargetProductList);  
  131.     ParseParamHex(configFilename, TargetClass);  
  132.     ParseParamHex(configFilename, DefaultVendor);  
  133.     ParseParamHex(configFilename, DefaultProduct);  
  134.     ParseParamBool(configFilename, DetachStorageOnly);  
  135.     ParseParamBool(configFilename, HuaweiMode);  
  136.     ParseParamBool(configFilename, SierraMode);  
  137.     ParseParamBool(configFilename, SonyMode);  
  138.     ParseParamBool(configFilename, GCTMode);  
  139.     ParseParamHex(configFilename, MessageEndpoint);  
  140.     ParseParamString(configFilename, MessageContent);  
  141.     ParseParamHex(configFilename, NeedResponse);  
  142.     ParseParamHex(configFilename, ResponseEndpoint);  
  143.     ParseParamHex(configFilename, ResetUSB);  
  144.     ParseParamHex(configFilename, InquireDevice);  
  145.     ParseParamInt(configFilename, CheckSuccess);  
  146.     ParseParamHex(configFilename, Interface);  
  147.     ParseParamHex(configFilename, Configuration);  
  148.     ParseParamHex(configFilename, AltSetting);   
  149.     // TargetProductList has priority over TargetProduct  
  150.     if (strlen(TargetProductList))  
  151.         TargetProduct = 0;   
  152. config_read = 1;  
  153. }  
  154. //  
  155. //  
  156. ////////  
  157. /***************************************************************** 
  158. main函数包括上一篇中讲到的读取命令行参数,如果命令行参数使用了-W等参数,则直接调用默认的配置文件,否则,后面的参数将由命令行传入。 
  159. ******************************************************************/  
  160. //  
  161. //////////////////  
  162. int main(int argc, char **argv)  
  163. {  
  164.      // Check command arguments, use params instead of config file when given  
  165.     switch (readArguments(argc, argv)) {  
  166.         case 0:                        // no argument or -W, -q or -s  
  167.             readConfigFile("/etc/usb_modeswitch.conf");  
  168.             break;  
  169.         default:                    // one or more arguments except -W, -q or -s   
  170.             if (!config_read)        // if arguments contain -c, the config file was already processed  
  171.                 if (verbose) printf("Taking all parameters from the command line/n/n");  
  172.     }  
  173. }  
  174.    
   

 

三.以上程序思想

 

由于c标准库函数提供了一大把可用的函数调用供我们使用,所以我们可以使用各种可用的函数来实现以上功能,但其基本实现思想都是一样的:每次只读取一行,然后将这一行放入一个buffer中,,然后根据我们设置的配置文件格式进行字符串处理就OK了,其中主要就是依靠strtok函数返回这一buffer中的各段数据,比如 NAME = anson,则需要使用strtok函数返回"NAME","=","anson"三段,当然是依次来,前面如果与传入的参数项目"NAME"不匹配也就没有做下去的必要了,可以读取下一个参数项了。"NAME"是项目类型,“anson”则是项目值,如果传入的参数查询项与"NAME"匹配,则可以取后面的值"anson"。因为实现比较容易,就不详细贴出实例了。

 

 

 

 

 我们在程序编写中往往会遇到这样的情况,程序运行中我们会读取配置文件,从中读取我们程序需要的各种参数与配置信息,我一般采用读取配置文件和使用Berkeley db的方式,这两种方式的移植性都较好,当然前者更好,但是后者也有它的好处,它可以很好的处理配置信息的读取等等,但是它需要bdb库的支持,虽然库很小,但对我们来讲,还是麻烦,所以我们一般还是采用读取配置文件的方式,而读取配置文件的方式又有很多种,本篇就讲第一种方式,也是我最常用的一种方式,单纯的用C库函数来实现.

.示例

这里我们还是以usb_modeswitch的代码为例子进行讲解,首先看一下它的配置文件:usb_modeswitch.conf,其中的格式如下部分所示:

[c-sharp]  view plain copy
  1. ########################################################  
  2. # Huawei E630  
  3. #  
  4. # There seem to be modem-only variants around - no storage,  
  5. # no switching  
  6. #  
  7. # Contributor: Joakim Wenrgren   
  8. ;DefaultVendor=  0x1033  
  9. ;DefaultProduct= 0x0035   
  10. ;TargetVendor=   0x12d1  
  11. ;TargetProduct=  0x1003   
  12. # choose one of these:  
  13. ;HuaweiMode=1  
  14. ;DetachStorageOnly=1   
  15. ########################################################  

.读取此配置文件的程序实现 

 

[cpp]  view plain copy
  1. /////////////////////////////////////////////////////////  
  2. //  
  3. /********************************************************** 
  4. //真正的配置文件解析函数,它的实现很简单,就不详细分析了,主要就是利用几个标准库函数就可以处理了, 
  5. //主要包括:fgets,strchr ,strcspn ,strrchr ,strspn , 
  6. // 
  7. // 
  8. **********************************************************/  
  9. /***************************************/  
  10. // the parameter parsing stuff  
  11. /***************************************/  
  12. char* ReadParseParam(const char* FileName, char *VariableName)  
  13. {  
  14.     static char Str[LINE_DIM];  
  15.     char *VarName, *Comment=NULL, *Equal=NULL;  
  16.     char *FirstQuote, *LastQuote, *P1, *P2;  
  17.     int Line=0, Len=0, Pos=0;  
  18.     FILE *file=fopen(FileName, "r");  
  19.       
  20.     if (file==NULL) {  
  21.         fprintf(stderr, "Error: Could not find file %s/n/n", FileName);  
  22.         exit(1);  
  23.     }  
  24.   
  25.     while (fgets(Str, LINE_DIM-1, file) != NULL) {  
  26.         Line++;  
  27.         Len=strlen(Str);  
  28.         if (Len==0) goto Next;  
  29.         if (Str[Len-1]=='/n' or Str[Len-1]=='/r') Str[--Len]='/0';  
  30.         Equal = strchr (Str, '=');          // search for equal sign  
  31.         Pos = strcspn (Str, ";#!");         // search for comment  
  32.         Comment = (Pos==Len) ? NULL : Str+Pos;  
  33.         if (Equal==NULL or ( Comment!=NULL and Comment<=Equal)) goto Next;   // Only comment  
  34.         *Equal++ = '/0';  
  35.         if (Comment!=NULL) *Comment='/0';  
  36.   
  37.         // String  
  38.         FirstQuote=strchr (Equal, '"');     // search for double quote char  
  39.         LastQuote=strrchr (Equal, '"');  
  40.         if (FirstQuote!=NULL) {  
  41.             if (LastQuote==NULL) {  
  42.                 fprintf(stderr, "Error reading parameter file %s line %d - Missing end quote./n", FileName, Line);  
  43.                 goto Next;  
  44.             }  
  45.             *FirstQuote=*LastQuote='/0';  
  46.             Equal=FirstQuote+1;  
  47.         }  
  48.           
  49.         // removes leading/trailing spaces  
  50.         Pos=strspn (Str, " /t");  
  51.         if (Pos==strlen(Str)) {  
  52.             fprintf(stderr, "Error reading parameter file %s line %d - Missing variable name./n", FileName, Line);  
  53.             goto Next;      // No function name  
  54.         }  
  55.         while ((P1=strrchr(Str, ' '))!=NULL or (P2=strrchr(Str, '/t'))!=NULL)  
  56.             if (P1!=NULL) *P1='/0';  
  57.             else if (P2!=NULL) *P2='/0';  
  58.         VarName=Str+Pos;  
  59.         //while (strspn(VarName, " /t")==strlen(VarName)) VarName++;  
  60.   
  61.         Pos=strspn (Equal, " /t");  
  62.         if (Pos==strlen(Equal)) {  
  63.             fprintf(stderr, "Error reading parameter file %s line %d - Missing value./n", FileName, Line);  
  64.             goto Next;      // No function name  
  65.         }  
  66.         Equal+=Pos;  
  67.   
  68.         if (strcmp(VarName, VariableName)==0) {     // Found it  
  69.             fclose(file);  
  70.             return Equal;  
  71.         }  
  72.         Next:;  
  73.     }  
  74.       
  75.     // not found  
  76. //  fprintf(stderr, "Error reading parameter file %s - Variable %s not found.",   
  77. //              FileName, VariableName);  
  78.     fclose(file);  
  79.     return NULL;  
  80. }  
  81.   
  82.   
  83. //  
  84. //  
  85. //  
  86. //*根据各种将要读取参数的类型,我们定义如下宏,用于各种不同的处理。*/  
  87. /********************************************************************* 
  88. 注意:对于函数的带参宏定义,没有使用过的人可能会有疑问,在带参宏定义中,形式参数不分配内存单元,因此不必作类型定义。而宏调用中的实参有具体的值。要用它们去代换形参,因此必须作类型说明。这是与函数中的情况不同的。在函数中,形参和实参是两个不同的量,各有自己的作用域,调用时要把实参值赋予形参,进行“值传递”。而在带参宏中,只是符号代换,不存在值传递的问题。 
  89.  
  90. ***********************************************************************/  
  91. //////////  
  92. //  
  93. //  
  94. extern char* ReadParseParam(const char* FileName, char *VariableName);  
  95.   
  96. extern char *TempPP;  
  97. //字符串参数  
  98. #define ParseParamString(ParamFileName, Str) /  
  99.     if ((TempPP=ReadParseParam((ParamFileName), #Str))!=NULL) /  
  100.         strcpy(Str, TempPP); else Str[0]='/0'  
  101. //整数参数        
  102. #define ParseParamInt(ParamFileName, Int) /  
  103.     if ((TempPP=ReadParseParam((ParamFileName), #Int))!=NULL) /  
  104.         Int=atoi(TempPP)  
  105. //16进制整数参数  
  106. #define ParseParamHex(ParamFileName, Int) /  
  107.     if ((TempPP=ReadParseParam((ParamFileName), #Int))!=NULL) /  
  108.         Int=strtol(TempPP, NULL, 16)  
  109. //浮点数参数  
  110. #define ParseParamFloat(ParamFileName, Flt) /  
  111.     if ((TempPP=ReadParseParam((ParamFileName), #Flt))!=NULL) /  
  112.         Flt=atof(TempPP)  
  113. //布尔型参数  
  114. #define ParseParamBool(ParamFileName, B) /  
  115.     if ((TempPP=ReadParseParam((ParamFileName), #B))!=NULL) /  
  116.         B=(toupper(TempPP[0])=='Y' || toupper(TempPP[0])=='T'|| TempPP[0]=='1'); else B=0  
  117.   
  118. //  
  119. //  
  120. //*************************************************************************  
  121. ////////////////////  
  122. 根据不同的参数类型和参数内容的性质(string,int,hex,bool?),调用不同的函数,实际上是调用同一函数只是进行不同的处理而以,由于这些处理很容易,故直接在宏定义定义成不同的函数了,使程序的条理更加清晰。  
  123. ***************************************************************************/  
  124. /////////////  
  125. void readConfigFile(const char *configFilename)  
  126. {  
  127.     if (verbose) printf("Reading config file: %s/n", configFilename);  
  128.     ParseParamHex(configFilename, TargetVendor);  
  129.     ParseParamHex(configFilename, TargetProduct);  
  130.     ParseParamString(configFilename, TargetProductList);  
  131.     ParseParamHex(configFilename, TargetClass);  
  132.     ParseParamHex(configFilename, DefaultVendor);  
  133.     ParseParamHex(configFilename, DefaultProduct);  
  134.     ParseParamBool(configFilename, DetachStorageOnly);  
  135.     ParseParamBool(configFilename, HuaweiMode);  
  136.     ParseParamBool(configFilename, SierraMode);  
  137.     ParseParamBool(configFilename, SonyMode);  
  138.     ParseParamBool(configFilename, GCTMode);  
  139.     ParseParamHex(configFilename, MessageEndpoint);  
  140.     ParseParamString(configFilename, MessageContent);  
  141.     ParseParamHex(configFilename, NeedResponse);  
  142.     ParseParamHex(configFilename, ResponseEndpoint);  
  143.     ParseParamHex(configFilename, ResetUSB);  
  144.     ParseParamHex(configFilename, InquireDevice);  
  145.     ParseParamInt(configFilename, CheckSuccess);  
  146.     ParseParamHex(configFilename, Interface);  
  147.     ParseParamHex(configFilename, Configuration);  
  148.     ParseParamHex(configFilename, AltSetting);   
  149.     // TargetProductList has priority over TargetProduct  
  150.     if (strlen(TargetProductList))  
  151.         TargetProduct = 0;   
  152. config_read = 1;  
  153. }  
  154. //  
  155. //  
  156. ////////  
  157. /***************************************************************** 
  158. main函数包括上一篇中讲到的读取命令行参数,如果命令行参数使用了-W等参数,则直接调用默认的配置文件,否则,后面的参数将由命令行传入。 
  159. ******************************************************************/  
  160. //  
  161. //////////////////  
  162. int main(int argc, char **argv)  
  163. {  
  164.      // Check command arguments, use params instead of config file when given  
  165.     switch (readArguments(argc, argv)) {  
  166.         case 0:                        // no argument or -W, -q or -s  
  167.             readConfigFile("/etc/usb_modeswitch.conf");  
  168.             break;  
  169.         default:                    // one or more arguments except -W, -q or -s   
  170.             if (!config_read)        // if arguments contain -c, the config file was already processed  
  171.                 if (verbose) printf("Taking all parameters from the command line/n/n");  
  172.     }  
  173. }  
  174.    
   

 

三.以上程序思想

 

由于c标准库函数提供了一大把可用的函数调用供我们使用,所以我们可以使用各种可用的函数来实现以上功能,但其基本实现思想都是一样的:每次只读取一行,然后将这一行放入一个buffer中,,然后根据我们设置的配置文件格式进行字符串处理就OK了,其中主要就是依靠strtok函数返回这一buffer中的各段数据,比如 NAME = anson,则需要使用strtok函数返回"NAME","=","anson"三段,当然是依次来,前面如果与传入的参数项目"NAME"不匹配也就没有做下去的必要了,可以读取下一个参数项了。"NAME"是项目类型,“anson”则是项目值,如果传入的参数查询项与"NAME"匹配,则可以取后面的值"anson"。因为实现比较容易,就不详细贴出实例了。

 

 

 

 

你可能感兴趣的:(String,File,null,buffer,interface,hex)