| 
                            
                                  前言????前面其实我们已经掌握了对配置文件,文本文件的读写函数和方法,如果一个INI文件只有少许的键值对,那么用内置函数也还凑合,但是当INI文件中的键值对多了起来,内置函数一个一个去读写的方式就非常繁琐,本节就针对这种情况对INI文件的读写方式进行升级,以达到快速便捷读写多键值对的情况???? 演示软硬件环境 Win10 x64 ; CANoe 11 SP2 x64 批量读取代码讲解1?? 本节演示仍然基于 bmw2.cfg ,新增一个Nework Node ,用于按键触发测试 
 2?? 下图的test.ini 文件是我们的测试文件,键值对有很多 
 3?? 我们按照编程习惯,控制语句放在IniAuto.can文件中,函数和全局变量放在IniAuto.cin文件中IniAuto.can中代码: 
	
		
			| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | /*@!Encoding:936*/ includes {   #include "IniAuto.cin" }   on key 'u' {   write("*****press u***********");   getKeyValueFromINI(Ini_data_path,var_Ini_Data);   if(1) //debug check values   {     int i ;     write ("************************Debug data******************************");     for(i = 0 ;i < var_Ini_Data.items ;i++)     {       write ("*******section:%s*******",var_Ini_Data.section[i]);       write ("*******index:%d***keys:%s*******",i,var_Ini_Data.keys[i]);       write ("*******index:%d***values:%s*******",i,var_Ini_Data.values[i]);     }     } } |  4?? 头文件 IniAuto.cin中代码: 
	
		
			| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | /*@!Encoding:936*/   variables {      char Ini_data_path[100] = ".//TestModule//IniAutoCode//test.ini";      char Ini_data_path_out[100] = ".//TestModule//IniAutoCode//test_out.ini";      const int max_items = 200 ;     const int max_keys_size = 50 ;     const int max_values_size = 300 ;         struct Ini_Data // record Ini data   {     int  items;     char section[max_items][max_keys_size];     char keys   [max_items][max_keys_size];     char values [max_items][max_values_size];      };    struct Ini_Data var_Ini_Data; }   /*************************************************************************************************** ---------------------------------------------------------------------------------------------------- Revision history: Date   2022-2-18 Author mayixiaobing 批量读INI ---------------------------------------------------------------------------------------------------- ***************************************************************************************************/ int getKeyValueFromINI(char FilePath[], struct Ini_Data Temp_var_Ini_Data) {   int i,j,glbHandle;   char buffer[max_values_size];   long section_find, key_find;   char section_temp[max_keys_size];   char keys_temp_1[max_keys_size]    ,keys_temp_2[max_keys_size];   char values_temp_1[max_values_size],values_temp_2[max_values_size];       glbHandle = OpenFileRead (FilePath,0);       if (glbHandle!=0 )   {       write("Open file :%s passed.",FilePath);     j = 0;           while(fileGetStringSZ(buffer,elcount(buffer),glbHandle)!=0)       {           section_find = strstr_regex(buffer, "\\[.*?\\]"); //用正则表达式匹配 []       if(section_find != -1)        {         ClearCharArray(section_temp);         substr_cpy (section_temp,buffer,1,strlen(buffer)-2,  elcount(buffer));//掐头去尾,去掉[]         continue ;        }               key_find = strstr(buffer, "=");                   if(key_find != -1)       {         ClearCharArray(keys_temp_1);ClearCharArray(keys_temp_2); //临时字符串使用之前要初始化         substr_cpy (keys_temp_1,buffer,0,key_find,  elcount(buffer));// = 前的key         remove_space(keys_temp_1,keys_temp_2);                 //清除字符传中的空格                  ClearCharArray(values_temp_1);ClearCharArray(values_temp_2);         substr_cpy (values_temp_1,buffer,key_find+1,strlen(buffer) - key_find, elcount(buffer));//= 后的value         remove_space(values_temp_1,values_temp_2);           strncpy (Temp_var_Ini_Data.section[j],section_temp  ,elcount(Temp_var_Ini_Data.section[j]));         strncpy (Temp_var_Ini_Data.keys[j]   ,keys_temp_2   ,elcount(Temp_var_Ini_Data.keys[j]));         strncpy (Temp_var_Ini_Data.values[j] ,values_temp_2 ,elcount(Temp_var_Ini_Data.values[j]));         j++;  // index ++         }               }      Temp_var_Ini_Data.items = j ;  // 最后统计多少行数据     fileClose (glbHandle);    }    else   {     write("Read file :%s failed.",FilePath);     return 0; //failed      }   return 1; //passed }   /*************************************************************************************************** ---------------------------------------------------------------------------------------------------- Revision history: Date   2022-2-18 Author mayixiaobing 去除字符串的空格 ---------------------------------------------------------------------------------------------------- ***************************************************************************************************/ void remove_space(char input_c[],char out_c[]) {       int i,j ;   j=0;       for(i = 0; i< strlen(input_c);i++)   {     if (input_c[i] != ' ')     {       out_c[j] = input_c[i];       j++;     }   } } /*************************************************************************************************** ---------------------------------------------------------------------------------------------------- Revision history: Date   2022-2-18 Author mayixiaobing 字符串初始化 ---------------------------------------------------------------------------------------------------- ***************************************************************************************************/ void ClearCharArray(char arrIn[]) {     int i, length;   length = strlen(arrIn);   for(i=length;i>=0;i--){    arrIn[i]=0x00;   } } |  5?? 头文件 IniAuto.cin中不良定义解释说明:因为涉及到批量操作,所有都化整为零,全部key/value的数据类型都视为字符串操作,实际代码中,如果有整形浮点型的,请再进行格式转换
 
 6?? 头文件 IniAuto.cin中 getKeyValueFromINI 函数的注释 
 7?? 按键’u‘,看下测试结果: 我们已经把ini的键值对都转换为了CAPl的数组类型,那么这样我们在下一步无论怎么去批量读,改写,删除 
 批量写入代码讲解
	1?? 我们读取了之后,可能的操作是改写,删除,添加,甚至是新建操作,那么这一系列操作之后,我们还要保存到原来的INI文件的。2?? 我们按照编程习惯,控制语句放在IniAuto.can文件中,函数和全局变量放在IniAuto.cin文件中 IniAuto.can中的增加的代码: 
	
		
			| 1 2 3 4 5 6 7 | /*@!Encoding:936*/ on key 'm' {   write("*****press m***********");       SetKeyValueToINI(Ini_data_path_out,var_Ini_Data); } |  3?? 头文件 IniAuto.cin中增加的代码: 
	
		
			| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | /*@!Encoding:936*/   /*************************************************************************************************** ---------------------------------------------------------------------------------------------------- Revision history: Date   2022-2-18 Author mayixiaobing 批量写入Key/value 到INI ---------------------------------------------------------------------------------------------------- ***************************************************************************************************/ int SetKeyValueToINI(char FilePath[], struct Ini_Data Temp_var_Ini_Data) {   long retVal;   int i,j,glbHandle;   char buffer[max_values_size];   char section_temp[max_items][max_keys_size];   char tempText[max_values_size];         ClearCharArray(section_temp);   glbHandle = OpenFileWrite(FilePath,0); // 写入文件,以覆盖源文件的形式       if (glbHandle!=0 )   {       write("Open file :%s passed.",FilePath);     j = 0 ;     for(i=0;i< Temp_var_Ini_Data.items ; i++)     {                           if((strncmp(Temp_var_Ini_Data.section[i],"",strlen(Temp_var_Ini_Data.section[i])) !=0)&&          (strncmp(Temp_var_Ini_Data.keys[i],   "",strlen(Temp_var_Ini_Data.keys[i]))    !=0)) //section、key 值不为空,写入                 {         /* section_temp是一个临时字符串数组,用来存储已经写过的section,         每次执行写入前会先检查下是否已经写过了,如果没写过,就添加到这个素组中,如果在这个数组中找到了,就不再写入Ini了         */         retVal = SeachValueInArrary(Temp_var_Ini_Data.section[i],section_temp );                   if (retVal== -1)         {                 snprintf(tempText, elcount(tempText), "\n[%s]\n", Temp_var_Ini_Data.section[i]);           filePutString (tempText, elcount(tempText),glbHandle);                 strncpy (section_temp[j],Temp_var_Ini_Data.section[i]  ,elcount(section_temp[j]));           j++ ;         }           snprintf(tempText, elcount(tempText), "%s = %s\n", Temp_var_Ini_Data.keys[i],Temp_var_Ini_Data.values[i]); //写入键值对         filePutString (tempText, elcount(tempText),glbHandle);       }     }                  fileClose (glbHandle);    }    else   {     write("Write file :%s failed.",FilePath);     return 0; //failed      }   return 1; //passed }   /*************************************************************************************************** ---------------------------------------------------------------------------------------------------- Revision history: Date   2022-2-18 Author mayixiaobing 在一个中查找指定值 ---------------------------------------------------------------------------------------------------- ***************************************************************************************************/ long SeachValueInArrary(char target[] ,char source[][]) {       int i ;       for(i= 0;i<elcount(source);i++)   {     if(strncmp(target,source[i],strlen(target)) ==0 )     {       //write("Seached value %s in the arrary and the index is %d",target,i);       return i;     }   }   return -1 ; } |  4?? 我们再在按键’u‘,读取了INI文件后,什么操都不要做,然会按下’m‘,看下测试结果已经都写进来了 
 更新INI文件键值对
	1?? 我们读取了之后,可能的操作是改写其中的某个键值对,2?? 我们按照编程习惯,控制语句放在IniAuto.can文件中,函数和全局变量放在IniAuto.cin文件中 IniAuto.can中的增加的代码: 
	
		
			| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | on key 'i' //改写key {     write("*****press %c***********",this);   updateINIvalue(0,"Tester ","Runer","",var_Ini_Data,Ini_data_path_out); // 改写第一个键值对的key,索引值是0,把Tester改成Runer     }   on key 'p' //改写value {     write("*****press %c***********",this);   updateINIvalue(0,"Tester","Tester","https://blog.csdn.net/qq_34414530",var_Ini_Data,Ini_data_path_out); // 改写第一个键值对的value,索引值是0,     }   on key 'k' //改写value {     write("*****press %c***********",this);   updateINIvalue(0,"Tester","Runer","https://blog.csdn.net/qq_34414530",var_Ini_Data,Ini_data_path_out); // 对key和value同时操做     } |  3?? 头文件 IniAuto.cin中增加的代码: 
	
		
			| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | /*************************************************************************************************** ---------------------------------------------------------------------------------------------------- Revision history: Date   2022-2-18 Author mayixiaobing 更改键值对,不完善,异常捕捉代码需完善 ---------------------------------------------------------------------------------------------------- ***************************************************************************************************/   void updateINIvalue(long index ,char section[],char keys[],char values[],struct Ini_Data Temp_var_Ini_Data,char FilePath[]) {       if(index < Temp_var_Ini_Data.items)   {     if(strncmp(section,"",strlen(section)) !=0)// 不等于空,就写入     {       strncpy (Temp_var_Ini_Data.section[index],section  ,elcount(Temp_var_Ini_Data.section[index]));     }     if(strncmp(keys,"",strlen(keys)) !=0)// 不等于空,就写入     {       strncpy (Temp_var_Ini_Data.keys[index]   ,keys     ,elcount(Temp_var_Ini_Data.keys[index]));     }     if(strncmp(values,"",strlen(values)) !=0)// 不等于空,就写入     {       strncpy (Temp_var_Ini_Data.values[index] ,values   ,elcount(Temp_var_Ini_Data.values[index]));     }                SetKeyValueToINI(FilePath, Temp_var_Ini_Data); //保存   }   else   {     write("index out of range.");   } } |  4?? 我们看下测试结果 ???? 先按键’u‘读取原始INI,然会按下’i‘,改写Key值: 
 ???? 先按键’u‘读取原始INI,然会按下p,改写value值: 
 ???? 先按键’u‘读取原始INI,然会按下k,改写key/value值: 
 删除INI文件键值对
	1?? 我们读取了之后,可能的操作是改写其中的删除某个键值对,2?? 我们按照编程习惯,控制语句放在IniAuto.can文件中,函数和全局变量放在IniAuto.cin文件中 IniAuto.can中的增加的代码: 
	
		
			| 1 2 3 4 5 6 | on key 'h' //删除键值对 {     write("*****press %c***********",this);   deleteINIItem(3,var_Ini_Data,Ini_data_path_out); // 删除Peed = 20.5 } |  3?? 头文件 IniAuto.cin中增加的代码: 
	
		
			| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | /*************************************************************************************************** ---------------------------------------------------------------------------------------------------- Revision history: Date   2022-2-18 Author mayixiaobing 删除键值对,这里根据索引去删除,也可以再重载函数根据key值或者value值去删除 当然也可以重载函数,传入索引数组,去批量删除, 后期有时间再继续完善 ---------------------------------------------------------------------------------------------------- ***************************************************************************************************/   void deleteINIItem(long index ,struct Ini_Data Temp_var_Ini_Data,char FilePath[]) {       if(index < Temp_var_Ini_Data.items)   {     strncpy (Temp_var_Ini_Data.section[index],""  ,elcount(Temp_var_Ini_Data.section[index]));      strncpy (Temp_var_Ini_Data.keys[index]   ,""  ,elcount(Temp_var_Ini_Data.keys[index]));     strncpy (Temp_var_Ini_Data.values[index] ,""  ,elcount(Temp_var_Ini_Data.values[index]));               SetKeyValueToINI(FilePath, Temp_var_Ini_Data); //保存   }   else   {     write("index out of range.");   } } |  4?? 我们看下测试结果 ???? 先按键’u‘读取原始INI,然会按下’h‘,删除Peed = 20.5: 
 增加INI文件键值对
	1?? 我们读取了之后,可能的操作是增加某个键值对2?? 我们按照编程习惯,控制语句放在IniAuto.can文件中,函数和全局变量放在IniAuto.cin文件中 IniAuto.can中的增加的代码: 
	
		
			| 1 2 3 4 5 6 7 8 9 10 11 12 | on key 'j' //增加键值对 {     write("*****press %c***********",this);   appendINIItem("Number","place","shanghai",var_Ini_Data,Ini_data_path_out); // 在[Number] 下增加一个place = shanghai, }   on key 'g' //增加键值对,新的section {   write("*****press %c***********",this);   appendINIItem("Position","place","shanghai",var_Ini_Data,Ini_data_path_out); // 在[Number] 下增加一个place = shanghai, } |  3?? 头文件 IniAuto.cin中增加的代码: 
	
		
			| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | /*************************************************************************************************** ---------------------------------------------------------------------------------------------------- Revision history: Date   2022-2-18 Author mayixiaobing 增加键值对,下面的代码支持加入新的section,如果要在已有的section ---------------------------------------------------------------------------------------------------- ***************************************************************************************************/   void appendINIItem(char section[],char keys[],char values[],struct Ini_Data Temp_var_Ini_Data,char FilePath[]) {      long retIndex ;   long items;   long i ;                         if((strncmp(section,"",strlen(section)) !=0)&&      (strncmp(keys   ,"",strlen(keys))    !=0)) //section、key 值不为空,写入        {             items = Temp_var_Ini_Data.items ;            retIndex = SeachValueInArrary(section,Temp_var_Ini_Data.section);                if (retIndex == -1)//如果是新的section,直接尾处追加     {                  strncpy (Temp_var_Ini_Data.section[items],section  ,elcount(Temp_var_Ini_Data.section[items]));       strncpy (Temp_var_Ini_Data.keys[items]   ,keys     ,elcount(Temp_var_Ini_Data.keys[items]));       strncpy (Temp_var_Ini_Data.values[items] ,values   ,elcount(Temp_var_Ini_Data.values[items]));        }     else //如果是已有section,从索引处,向后顺移     {       for(i= items;i > retIndex ;i--)       {         strncpy (Temp_var_Ini_Data.section[i],Temp_var_Ini_Data.section[i-1]  ,elcount(Temp_var_Ini_Data.section[i]));         strncpy (Temp_var_Ini_Data.keys[i]   ,Temp_var_Ini_Data.keys[i-1]     ,elcount(Temp_var_Ini_Data.keys[i]));         strncpy (Temp_var_Ini_Data.values[i] ,Temp_var_Ini_Data.values[i-1]   ,elcount(Temp_var_Ini_Data.values[i]));             }       strncpy (Temp_var_Ini_Data.section[retIndex],section  ,elcount(Temp_var_Ini_Data.section[retIndex]));       strncpy (Temp_var_Ini_Data.keys[retIndex]   ,keys     ,elcount(Temp_var_Ini_Data.keys[retIndex]));       strncpy (Temp_var_Ini_Data.values[retIndex] ,values   ,elcount(Temp_var_Ini_Data.values[retIndex]));      }                         Temp_var_Ini_Data.items = items + 1;        SetKeyValueToINI(FilePath, Temp_var_Ini_Data); //保存   } } |  4?? 我们看下测试结果 ???? 先按键’u‘读取原始INI,然会按下’j‘,在已有的section新加一个key/value: 
 ???? 先按键’u‘读取原始INI,然会按下’g‘,新建section以及key/value: 
 新建INI文件1?? 我们也可以直接新建一个键值对文件,不需要提前读取 2?? 我们按照编程习惯,控制语句放在IniAuto.can文件中,函数和全局变量放在IniAuto.cin文件中 IniAuto.can中的增加的代码,下面是新增两个参数: 
	
		
			| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | on key 'f' //新建ini文件 {     write("*****press %c***********",this);   var_Ini_Data.items = 2;   strncpy (var_Ini_Data.section[0],"test"  ,elcount(var_Ini_Data.section[0]));   strncpy (var_Ini_Data.keys[0]   ,"para1" ,elcount(var_Ini_Data.keys[0]));   strncpy (var_Ini_Data.values[0] ,"1234"  ,elcount(var_Ini_Data.values[0]));       strncpy (var_Ini_Data.section[1],"test"  ,elcount(var_Ini_Data.section[0]));   strncpy (var_Ini_Data.keys[1]   ,"para2" ,elcount(var_Ini_Data.keys[0]));   strncpy (var_Ini_Data.values[1] ,"4567"  ,elcount(var_Ini_Data.values[0]));       SetKeyValueToINI(Ini_data_path_out,var_Ini_Data); } |  3?? 头文件IniAuto.cin中增加的代码: 4?? 我们看下测试结果 
 
 |