1. 程式人生 > >【轉】Linux下配置檔案讀取操作流程及其C程式碼實現

【轉】Linux下配置檔案讀取操作流程及其C程式碼實現

轉自:http://blog.csdn.net/zhouzhaoxiong1227/article/details/45563263#comments

一、概述
Linux具有免費、可靠、安全、穩定、多平臺等特點,因此深受廣大程式設計師的歡迎。
為了體現軟體產品的靈活性,可新增配置檔案存放某些重要的引數,在部署的時候根據實際的安裝環境對每個配置項的值進行設定。這就要求程式能夠準確讀取到各個配置項的值。
本文詳細介紹了Linux下配置檔案的讀取方法及讀取操作的C程式碼實現,為相關的軟體開發工作的開展提供了有益的參考。

二、配置檔案介紹
為了便於程式處理,對配置檔案的命名及內容格式有一些約定,具體如下:
第一,配置檔案的字尾為ini,如本文中使用到的配置檔案為:Config.ini。
第二,配置檔案的內容由段名、註釋和配置項組成,其中,段名由[]括起來,註釋的內容以分號(;)開頭,配置項採用等號(=)進行賦值。
本文使用的配置檔案“Config.ini”包含的具體內容如下:

[EMPLOYEEINFO]
;the name of employee
EmployeeName=wang
;the age of employee
EmployeeAge=25

[EMPLOYERINFO]
;the name of employer
EmployerName=zhou
;the age of employer
EmployerAge=38
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

三、配置檔案讀取操作總體流程
實現配置檔案讀取操作的程式流程如圖1所示。
這裡寫圖片描述
圖1 配置檔案讀取操作程式流程

四、配置檔案讀取操作重要流程
1.獲取配置檔案的全路徑
在本文中,配置檔案存放的全路徑為:/home/zhou/zhouzx/GetConfig/ Config.ini。實現獲取配置檔案的全路徑的程式函式為GetCompletePath(具體程式碼見後)。
說明:
(1) 函式getenv用來獲取某引數的環境變數的內容。getenv(“HOME”)用於獲取程式所在的當前使用者的全路徑。例如,本程式放在了zhou使用者下,那麼getenv(“HOME”)的值就為“/home/zhou”。
(2) Linux下目錄之間的分隔符為“/”,這個與Windows下的分隔符有區別。

2.匹配段名和配置項名,並獲取配置項的值
程式首先找到段名,然後在該段之下去匹配配置項名,最後獲取配置項的值。
程式流程如圖2所示。
這裡寫圖片描述
圖2 獲取配置項值的程式流程

實現該功能的程式函式為GetStringContentValue(具體程式碼見後)。

五、對配置檔案讀取操作的測試
為了對編寫的配置檔案讀取操作程式進行測試,定義了員工資訊結構體和僱主資訊結構體,分別用於存放從配置檔案中讀取到的員工資訊和僱主資訊。在main函式中將獲取到的資訊打印出來,以此來檢查程式操作的正確性。

六、C程式實現
本程式命名為“GetConfig.c”,具體程式碼如下:

/********************
************************************************** * 版權所有 (C)2015, Zhou Zhaoxiong。 * * 檔名稱:GetConfig.c * 檔案標識:無 * 內容摘要:演示Linux下配置檔案的讀取方法 * 其它說明:無 * 當前版本:V1.0 * 作 者:Zhou Zhaoxiong * 完成日期:20150507 * **********************************************************************/ #include <stdio.h> #include <stdlib.h> #include <string.h> // 資料型別重定義 typedef unsigned char UINT8; typedef signed int INT32; typedef unsigned int UINT32; // 員工資訊結構體定義 typedef struct { UINT8 szEmployeeName[128]; // 員工姓名 INT32 iEmployeeAge; // 員工年齡 } T_EmployeeInfo; // 僱主資訊結構體定義 typedef struct { UINT8 szEmployerName[128]; // 僱主姓名 INT32 iEmployerAge; // 僱主年齡 } T_EmployerInfo; // 函式宣告 void GetCompletePath(UINT8 *pszConfigFileName, UINT8 *pszWholePath); 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); INT32 main(); /********************************************************************** * 功能描述:主函式 * 輸入引數:無 * 輸出引數:無 * 返 回 值:無 * 其它說明:無 * 修改日期 版本號 修改人 修改內容 * --------------------------------------------------------------- * 20150507 V1.0 Zhou Zhaoxiong 建立 ***********************************************************************/ INT32 main() { T_EmployeeInfo tEmployeeInfo = {0}; T_EmployerInfo tEmployerInfo = {0}; // 獲取並列印員工資訊 // 獲取員工姓名 GetConfigFileStringValue("EMPLOYEEINFO", "EmployeeName", "", tEmployeeInfo.szEmployeeName, sizeof(tEmployeeInfo.szEmployeeName), "Config.ini"); // 獲取員工年齡 tEmployeeInfo.iEmployeeAge = GetConfigFileIntValue("EMPLOYEEINFO", "EmployeeAge", 20, "Config.ini"); if (tEmployeeInfo.iEmployeeAge == -1) // 判斷獲取到的年齡是否正確 { printf("Get EmployeeAge failed!\n"); return -1; } // 列印讀取到的員工姓名和年齡 printf("EmployeeName is %s, EmployeeAge is %d\n", tEmployeeInfo.szEmployeeName, tEmployeeInfo.iEmployeeAge); // 獲取並列印僱主資訊 // 獲取僱主姓名 GetConfigFileStringValue("EMPLOYERINFO", "EmployerName", "", tEmployerInfo.szEmployerName, sizeof(tEmployerInfo.szEmployerName), "Config.ini"); // 獲取員工年齡 tEmployerInfo.iEmployerAge = GetConfigFileIntValue("EMPLOYERINFO", "EmployerAge", 30, "Config.ini"); if (tEmployerInfo.iEmployerAge == -1) // 判斷獲取到的年齡是否正確 { printf("Get EmployerAge failed!\n"); return -1; } // 列印讀取到的員工姓名和年齡 printf("EmployerName is %s, EmployerAge is %d\n", tEmployerInfo.szEmployerName, tEmployerInfo.iEmployerAge); return 0; } /********************************************************************** * 功能描述: 獲取配置檔案完整路徑(包含檔名) * 輸入引數: pszConfigFileName-配置檔名 pszWholePath-配置檔案完整路徑(包含檔名) * 輸出引數: 無 * 返 回 值: 無 * 其它說明: 無 * 修改日期 版本號 修改人 修改內容 * ------------------------------------------------------------------ * 20150507 V1.0 Zhou Zhaoxiong 建立 ********************************************************************/ void GetCompletePath(UINT8 *pszConfigFileName, UINT8 *pszWholePath) { UINT8 *pszHomePath = NULL; UINT8 szWholePath[256] = {0}; // 先對輸入引數進行異常判斷 if (pszConfigFileName == NULL || pszWholePath == NULL) { printf("GetCompletePath: input parameter(s) is NULL!\n"); return; } pszHomePath = (UINT8 *)getenv("HOME"); // 獲取當前使用者所在的路徑 if (pszHomePath == NULL) { printf("GetCompletePath: Can't find home path!\n"); return; } // 拼裝配置檔案路徑 snprintf(szWholePath, sizeof(szWholePath)-1, "%s/zhouzx/GetConfig/%s", pszHomePath, pszConfigFileName); strncpy(pszWholePath, szWholePath, strlen(szWholePath)); } /********************************************************************** * 功能描述: 獲取具體的字串值 * 輸入引數: fp-配置檔案指標 pszSectionName-段名, 如: GENERAL pszKeyName-配置項名, 如: EmployeeName iOutputLen-輸出快取長度 * 輸出引數: pszOutput-輸出快取 * 返 回 值: 無 * 其它說明: 無 * 修改日期 版本號 修改人 修改內容 * ------------------------------------------------------------------ * 20150507 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-輸出快取 * 返 回 值: 無 * 其它說明: 無 * 修改日期 版本號 修改人 修改內容 * ------------------------------------------------------------------ * 20150507 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-獲取失敗 * 其它說明: 無 * 修改日期 版本號 修改人 修改內容 * ------------------------------------------------------------------ * 20150507 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; }
  • 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
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336

七、檔案上傳
在Windows下將程式編寫好之後,使用filezilla軟體將“GetConfig.c”程式碼檔案和“Config.ini”配置檔案上傳到“/home/zhou/zhouzx/GetConfig”目錄下。

八、檔案編譯及執行結果
使用SecureCRT軟體登入到Linux下,轉到“/home/zhou/zhouzx/GetConfig”目錄下,執行“gcc -g -o GetConfig GetConfig.c”命令,生成“GetConfig”。然後再執行“GetConfig”命令,程式執行結果如下:

~/zhouzx/GetConfig> gcc -g -o GetConfig GetConfig.c
~/zhouzx/GetConfig> GetConfig
EmployeeName is wang, EmployeeAge is 25
EmployerName is zhou, EmployerAge is 38
  • 1
  • 2
  • 3
  • 4

九、總結
本文對Linux下配置檔案讀取操作的整個流程進行了詳細的介紹,並給出了實現該操作的C程式碼。程式中的GetConfigFileStringValue和GetConfigFileIntValue函式可作為API供其它需要讀取配置檔案的程式呼叫。

本人微信公眾號:zhouzxi,請掃描以下二維碼:
這裡寫圖片描述