C讀寫配置文件
在項目開發中,經常需要讀取應用配置文件的初始化參數,用於應用在啟動前進行一些初始化配置。比如:Eclipse,參數項包含主題、字體大小、顏色、Jdk安裝位置、自動提示等。Eclispe配置的文件格式是以鍵值對的方式存儲的,即:key=value的形式,下麵是Eclipse部份設置參數:
/instance/org.eclipse.jdt.ui/useQuickDiffPrefPage=true /instance/org.eclipse.jdt.ui/content_assist_proposals_foreground=0,0,0 /instance/org.eclipse.egit.core/GitRepositoriesView.GitDirectories=/Users/yangxin/Downloads/kakaolink-android/.git\:/Users/yangxin/Documents/workspace_web/tfyj/.git\: /instance/org.eclipse.wst.jsdt.ui/fontPropagated=true /instance/org.eclipse.debug.core/org.eclipse.debug.core.USE_STEP_FILTERS=true /instance/org.eclipse.jdt.core/org.eclipse.jdt.core.compiler.problem.assertIdentifier=error /instance/org.eclipse.ui.workbench/org.eclipse.jface.textfont=1|Monaco|14.0|0|COCOA|1|Monaco; @org.eclipse.jdt.ui=3.8.2.v20130107-165834 /instance/org.eclipse.cdt.ui/spelling_locale_initialized=true從Eclipse配置文件中可以看出,都是以xxxx=xxxxx,如最後一個配置項,key為/instance/org.eclipse.cdt.ui/spelling_locale_initialized,值為:true。在項目開發當中的也經常采用這種方式,筆者參考了Java的java.util.Properties類,設計了一個C的配置文件讀寫接口,供大家學習和使用。
1、定義接口頭文件(Properties.h)
//
// Properties.h
// 讀寫配置文件
//
// Created by 楊信 on 14-4-24.
// Copyright (c) 2014年 yangxin. All rights reserved.
//
#ifndef _______Properties_h
#define _______Properties_h
#ifdef _cplusplus
extern "C" {
#endif
// 初始化環境,成功返回0,失敗返回非0值
int init(const char *filepath,void **handle);
// 根據KEY獲取值,找到返回0,如果未找到返回非0值
int getValue(void *handle, const char *key, char *value);
// 修改key對應的屬性值,修改成功返回0,失敗返回非0值
int setValue(void *handle, const char *key, const char *value);
// 添加一個屬性,添加成功返回0,失敗返回非0值
int add(void *handle, const char *key, const char *value);
// 刪除一個屬性,刪除成功返回0,失敗返回非0值
int del(void *handle, const char *key);
// 獲取屬性文件中所有的key,獲取成功返回0,失敗返回非0值
int getKeys(void *handle, char ***keys, int *keyscount);
// 釋放所有key的內存空間,成功返回0,失敗返回非0值
int free_keys(char ***keys,int *keyscount);
// 獲取屬性文件中所有的值,成功返回0,失敗返回非0值
int getValues(void *handle, char ***values, int *valuescount);
// 釋放所有value的內存空間,成功返回0,失敗返回非0值
int free_values(char ***values, int *valuescount);
// 獲取屬性數量,成功返回0,失敗返回非0值
int getCount(void *handle, int *count);
// 釋放環境資源,成功返回0,失敗返回非0值
int release(void **handle);
#ifdef _cplusplus
}
#endif
#endif
2、實現頭文件的接口(Properteis.c)
//
// Properties.c
// 讀寫配置文件
//
// Created by 楊信 on 14-4-24.
// Copyright (c) 2014年 yangxin. All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Properties.h"
#define KEY_SIZE 128 // key緩衝區大小
#define VALUE_SIZE 128 // value緩衝區大小
#define LINE_BUF_SIZE 256 // 讀取配置文件中每一行的緩衝區大小
typedef struct Properties {
char *key;
char *value;
struct Properties *pNext;
}Properties;
typedef struct PROPS_HANDLE {
Properties *pHead; // 屬性鏈表頭節點
char *filepath; // 屬性文件路徑
}PROPS_HANDLE;
static int createPropsNode(Properties **props); // 創建一個節點
static int trimeSpace(const char *src,char *dest); // 去空格
static int saveConfig(const char *filepath,Properties *head); // 將修改或保存後的配置項保存到文件
// 初始化環境,成功返回0,失敗返回非0值
int init(const char *filepath,void **handle)
{
int ret = 0;
FILE *fp = NULL;
Properties *pHead = NULL,*pCurrent = NULL, *pMalloc = NULL;
PROPS_HANDLE *ph = NULL;
char line[LINE_BUF_SIZE]; // 存放讀取每一行的緩衝區
char keybuff[KEY_SIZE] = { 0 }; // 存放key的緩衝區
char valuebuff[VALUE_SIZE] = { 0 }; // 存放value的緩衝區
char *pLine = NULL; // 每行緩衝區數據的指針
if(filepath == NULL || handle == NULL)
{
ret = -1;
printf("fun init error:%d from (filepath == NULL || handler == NULL)\n",ret);
return ret;
}
ph = (PROPS_HANDLE *)malloc(sizeof(PROPS_HANDLE));
if (ph == NULL) {
ret = -2;
printf("fun init malloc handle error:%d",ret);
return ret;
}
memset(ph, 0, sizeof(PROPS_HANDLE));
// 打開文件
fp = fopen(filepath, "r");
if (!fp) {
ret = -3;
printf("fun init open file error:%d from %s\n",ret,filepath);
return ret;
}
// 創建頭節點
ret = createPropsNode(&pHead);
if (ret != 0) {
fclose(fp); // 關閉文件
printf("fun init create head node error:%d\n",ret);
return ret;
}
memset(pHead, 0, sizeof(Properties));
// 保存鏈表頭節點和文件路徑到handle中
ph->pHead = pHead;
ph->filepath = (char *)malloc(strlen(filepath) + 1);
strcpy(ph->filepath, filepath);
pCurrent = pHead;
// 讀取配置文件中的所有數據
while (!feof(fp)) {
if(fgets(line, LINE_BUF_SIZE, fp) == NULL)
{
break;
}
// 找等號
if ((pLine = strstr(line, "=")) == NULL) { // 沒有等號,繼續讀取下一行
continue;
}
// 循環創建節點
ret = createPropsNode(&pMalloc);
if (ret != 0) {
fclose(fp); // 關閉文件
release((void **)&ph); // 創建節點失敗,釋放所有資源
printf("create new node error:%d\n",ret);
return ret;
}
// 設置Key
memcpy(keybuff, line, pLine-line);
trimeSpace(keybuff, pMalloc->key); // 將keybuff去空格後放到pMallock.key中
// 設置Value
pLine += 1;
trimeSpace(pLine, valuebuff);
strcpy(pMalloc->value, valuebuff);
// 將新節點入鏈表
pMalloc->pNext = NULL;
pCurrent->pNext = pMalloc;
pCurrent = pMalloc; // 當前節點下移
// 重置key,value
memset(keybuff, 0, KEY_SIZE);
memset(valuebuff, 0, VALUE_SIZE);
}
// 設置環境句柄給調用者
*handle = ph;
// 關閉文件
fclose(fp);
return ret;
}
// 獲取屬性數量,成功返回0,失敗返回非0值
int getCount(void *handle, int *count)
{
int ret = 0,cn = 0;
PROPS_HANDLE *ph = NULL;
Properties *pCurrent = NULL;
if (handle == NULL || count == NULL) {
ret = -1;
printf("fun getCount error:%d from (handle == NULL || count == NULL)\n",ret);
return ret;
}
ph = (PROPS_HANDLE *)handle;
pCurrent = ph->pHead->pNext;
while (pCurrent != NULL) {
cn++;
pCurrent = pCurrent->pNext;
}
*count = cn;
return ret;
}
// 根據KEY獲取值,找到返回0,如果未找到返回非0值
int getValue(void *handle, const char *key, char *value)
{
int ret = 0;
PROPS_HANDLE *ph = NULL;
Properties *pCurrent = NULL;
if (handle == NULL || key == NULL || value == NULL) {
ret = -1;
printf("getValue error:%d from (handle == NULL || key == NULL || value == NULL)\n",ret);
return ret;
}
ph = (PROPS_HANDLE *)handle;
pCurrent = ph->pHead->pNext;
while (pCurrent != NULL) {
if (strcmp(pCurrent->key,key) == 0) {
break;
}
pCurrent = pCurrent->pNext;
}
if (pCurrent == NULL) {
ret = -2;
printf("fun getValue warning: not found the key:%s\n",key);
return ret;
}
strcpy(value, pCurrent->value);
return ret;
}
// 修改key對應的屬性值,修改成功返回0,失敗返回非0值
int setValue(void *handle, const char *key, const char *value)
{
int ret = 0;
PROPS_HANDLE *ph = NULL;
Properties *pCurrent = NULL;
if (handle == NULL || key == NULL || value == NULL) {
ret = -1;
printf("fun setValue error:%d from (handle == NULL || key == NULL || value == NULL)\n",ret);
return ret;
}
// 獲得環境句柄
ph = (PROPS_HANDLE *)handle;
// 從環境句柄中獲取頭節點
pCurrent = ph->pHead->pNext;
while (pCurrent != NULL) {
if (strcmp(pCurrent->key, key) == 0) { // 找到
break;
}
pCurrent = pCurrent->pNext;
}
if (pCurrent == NULL) { // 未找到key
ret = -2;
printf("fun setValue warning: not found the key:%s\n",key);
return ret;
}
// 修改key的value
strcpy(pCurrent->value, value);
if (strchr(value, '\n') == NULL) { // 加一個換行符
strcat(pCurrent->value, "\n");
}
// 將修改的配置項寫入到文件
ret = saveConfig(ph->filepath, ph->pHead);
return ret;
}
// 添加一個屬性,添加成功返回0,失敗返回非0值
int add(void *handle, const char *key, const char *value)
{
int ret = 0;
PROPS_HANDLE *ph = NULL;
Properties *pCurrent = NULL;
if (handle == NULL || key == NULL || value == NULL) {
ret = -1;
printf("fun add error:%d from (handle == NULL || key == NULL || value == NULL)\n",ret);
return ret;
}
ph = (PROPS_HANDLE *)handle;
//-----------如果key存在鏈表中,則直接修改,否則添加到鏈表中-----------//
pCurrent = ph->pHead;
while (pCurrent->pNext != NULL) {
if (strcmp(pCurrent->pNext->key,key) == 0) {
break;
}
pCurrent = pCurrent->pNext;
}
if (pCurrent->pNext != NULL) {
return setValue(handle, key, value);
}
//-----------key不存在,創建一個新的配置項,添加到鏈表中-----------//
Properties *pMalloc;
ret = createPropsNode(&pMalloc);
if (ret != 0) {
printf("fun add error:%d from malloc new node.",ret);
return ret;
}
strcpy(pMalloc->key, key);
if (strchr(pCurrent->value,'\n') == NULL) {
strcat(pCurrent->value, "\n");
}
strcpy(pMalloc->value, value);
if (strchr(value, '\n') == NULL) { // 加一個換行符
strcat(pMalloc->value, "\n");
}
pCurrent->pNext = pMalloc; // 新配置項入鏈表
// 將新配置項寫入到文件
ret = saveConfig(ph->filepath, ph->pHead);
return ret;
}
// 刪除一個屬性,刪除成功返回0,失敗返回非0值
int del(void *handle, const char *key)
{
int ret = 0;
PROPS_HANDLE *ph = NULL;
Properties *pCurrent = NULL, *pPrev = NULL;
if (handle == NULL || key == NULL) {
ret = -1;
printf("fun del error:%d from (handle == NULL || key == NULL)\n",ret);
return ret;
}
ph = (PROPS_HANDLE *)handle;
pPrev = ph->pHead;
pCurrent = ph->pHead->pNext;
while (pCurrent != NULL) {
if (strcmp(pCurrent->key, key) == 0) {
break;
}
pPrev = pCurrent; // 上一個節點下移
pCurrent = pCurrent->pNext; // 當前節點下移
}
if (pCurrent == NULL) { // 沒有找到
ret = -2;
printf("fun del warning:not found the key:%s\n",key);
return ret;
}
pPrev->pNext = pCurrent->pNext; // 從鏈表中刪除
free(pCurrent); // 釋放內存
pCurrent = NULL;
// 保存到文件
ret = saveConfig(ph->filepath, ph->pHead);
return ret;
}
// 獲取屬性文件中所有的key,獲取成功返回0,失敗返回非0值
int getKeys(void *handle, char ***keys, int *keyscount)
{
int ret = 0, count = 0, index = 0;
PROPS_HANDLE *ph = NULL;
Properties *pCurrent = NULL;
char **pKeys = NULL;
if (handle == NULL || keys == NULL || keyscount == NULL) {
ret = -1;
printf("fun getKeys error:%d from (handle == NULL || keys == NULL || keyscount == NULL) \n",ret);
return ret;
}
// 獲取配置項數量
ret = getCount(handle, &count);
if (ret != 0) {
printf("fun getKeys error:%d from getCount \n",ret);
return ret;
}
ph = (PROPS_HANDLE *)handle;
pCurrent = ph->pHead->pNext;
// 根據鏈表長度,申請內存空間
pKeys = (char **)malloc(sizeof(char *) * count);
if (pKeys == NULL) {
ret = -2;
printf("fun getKeys error:%d from malloc keys\n",ret);
return ret;
}
pCurrent = ph->pHead->pNext;
while (pCurrent != NULL) {
pKeys[index] = pCurrent->key;
pCurrent = pCurrent->pNext;
index++;
}
*keys = pKeys;
*keyscount = count;
return ret;
}
// 釋放所有key的內存空間,成功返回0,失敗返回非0值
int free_keys(char ***keys,int *keyscount)
{
int ret = 0;
if (keys == NULL || keyscount == NULL) {
ret = -1;
printf("fun free_keys error:%d from (keys == NULL || keyscount == NULL) \n",ret);
return ret;
}
free(*keys);
*keys = NULL;
*keyscount = 0;
return ret;
}
// 獲取屬性文件中所有的值,成功返回0,失敗返回非0值
int getValues(void *handle, char ***values, int *valuescount)
{
int ret = 0, count = 0, index = 0;
PROPS_HANDLE *ph = NULL;
Properties *pCurrent = NULL;
char **pValues = NULL;
if (handle == NULL || values == NULL || valuescount == NULL) {
ret = -1;
printf("fun getValues error:%d from (handle == NULL || values == NULL || valuescount == NULL)\n",ret);
return ret;
}
// 獲取配置項數量
ret = getCount(handle, &count);
if (ret != 0) {
printf("fun getValues error:%d from getCount \n",ret);
return ret;
}
// 申請內存空間,存放所有的value
pValues = (char **)malloc(sizeof(char *) * count);
if (pValues == NULL) {
ret = -2;
printf("fun getValues error:%d from malloc values\n",ret);
return ret;
}
ph = (PROPS_HANDLE *)handle;
pCurrent = ph->pHead->pNext;
while (pCurrent != NULL) {
pValues[index] = pCurrent->value;
pCurrent = pCurrent->pNext;
index++;
}
*values = pValues;
*valuescount = count;
return ret;
}
// 釋放所有value的內存空間,成功返回0,失敗返回非0值
int free_values(char ***values, int *valuescount)
{
int ret = 0;
if (values == NULL || valuescount == NULL) {
ret = -1;
printf("fun free_values error:%d from (values == NULL || valuescount == NULL) \n",ret);
return ret;
}
free(*values);
*values = NULL;
*valuescount = 0;
return ret;
}
// 釋放環境資源,成功返回0,失敗返回非0值
int release(void **handle)
{
int ret = 0;
PROPS_HANDLE *ph = NULL;
if(handle == NULL)
{
ret = -1;
printf("release error:%d from (handler == NULL)\n",ret);
return ret;
}
ph = (PROPS_HANDLE *)*handle;
// 釋放鏈表內存資源
Properties *pCurr = ph->pHead;
Properties *pTemp = NULL;
while (pCurr != NULL) {
if (pCurr->key != NULL) {
free(pCurr->key);
pCurr->key = NULL;
}
if (pCurr->value != NULL) {
free(pCurr->value);
pCurr->value = NULL;
}
pTemp = pCurr->pNext;
free(pCurr);
pCurr = pTemp;
}
// 釋放存放配置文件路徑分配的內存空間
if(ph->filepath != NULL)
{
free(ph->filepath);
ph->filepath = NULL;
}
// 釋放環境句柄本身
free(ph);
*handle = NULL; // 避免野指針
return ret;
}
// 去空格
static int trimeSpace(const char *src,char *dest)
{
int ret = 0;
if (src == NULL || dest == NULL) {
ret = -1;
printf("trimeSpace error:%d from (src == NULL || dest == NULL)\n",ret);
return ret;
}
const char *psrc = src;
unsigned long i = 0,j = strlen(psrc) - 1,len;
while (psrc[i] == ' ')
{
i++;
}
while (psrc[j] == ' ') {
j--;
}
len = j - i + 1;
memcpy(dest,psrc+i,len);
*(dest+len) = '\0';
return ret;
}
// 創建一個節點
static int createPropsNode(Properties **props)
{
int ret = 0;
Properties *p = NULL;
if (props == NULL) {
ret = -100;
printf("createProps error:%d from (props == NULL)\n",ret);
return ret;
}
p = (Properties *)malloc(sizeof(Properties));
if (p == NULL) {
ret = -200;
printf("createProps malloc %ld bytes error:%d\n",sizeof(Properties),ret);
return ret;
}
p->key = (char *)malloc(KEY_SIZE);
p->value = (char *)malloc(VALUE_SIZE);
p->pNext = NULL;
*props = p;
return ret;
}
// 保存到文件
static int saveConfig(const char *filepath,Properties *head)
{
int ret = 0,writeLen = 0;
FILE *fp = NULL;
Properties *pCurrent = NULL;
if (filepath == NULL || head == NULL) {
ret = -100;
printf("fun saveConfig error:%d from (filepath == NULL || head == NULL)\n",ret);
return ret;
}
fp = fopen(filepath,"w");
if (fp == NULL) {
ret = -200;
printf("fun saveConfig:open file error:%d from %s\n",ret,filepath);
return ret;
}
pCurrent = head->pNext;
while (pCurrent != NULL) {
writeLen = fprintf(fp, "%s=%s",pCurrent->key,pCurrent->value); // 返回寫入的字節數,出現錯誤返回一個負值
if (writeLen < 0) { //TODO 如果寫入失敗,如何將寫入的數據回退???
ret = -300;
printf("fun saveConfig err:%d from (%s=%s)\n",ret,pCurrent->key,pCurrent->value);
break;
}
pCurrent = pCurrent->pNext;
}
fclose(fp); // 關閉文件
return ret;
}
3、測試代碼(需要在項目根目錄創建props.txt)
//
// main.c
// 讀寫配置文件
//
// Created by 楊信 on 14-4-24.
// Copyright (c) 2014年 yangxin. All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "Properties.h"
int main(int argc, const char * argv[])
{
int ret;
void *handle;
const char *filepath = "/Users/yangxin/Desktop/props.txt";
// 初始化
ret = init(filepath, &handle);
if (ret != 0) {
printf("env init error:%d\n",ret);
return 0;
}
char valuebuf[128];
// 測試獲取配置項
ret = getValue(handle, "host", valuebuf);
if (ret == 0) {
printf("value=%s\n",valuebuf);
}
else {
printf("獲取值host的值失敗\n");
}
// 測試修改配置項
ret = setValue(handle, "version", "1.2.3");
if (ret == 0) {
printf("修改成功!\n");
}
else{
printf("修改失敗\n");
}
// 測試添加配置項
ret = add(handle, "pool_connection_countxx", "2000");
if (ret == 0) {
printf("添加成功!\n");
}
else{
printf("添加失敗\n");
}
// 測試刪除配置項
ret = del(handle, "connectionMax");
if (ret == 0) {
printf("刪除成功!\n");
}
else{
printf("刪除失敗\n");
}
// 測試獲取所有配置項的key
char **keys = NULL;
int keyscount;
ret = getKeys(handle, &keys, &keyscount);
if (ret == 0) {
printf("一共有%d個Key\n",keyscount);
for (int i =0; i<keyscount; i++) {
printf("%s\n",keys[i]);
}
}
// 釋放內存
ret = free_keys(&keys, &keyscount);
if (ret == 0) {
printf("keys釋放內存成功!\n");
}
// 測試獲取所有配置項的value
char **values = NULL;
int valuescount;
ret = getValues(handle, &values, &valuescount);
if (ret == 0) {
printf("一共有%d個Value\n",valuescount);
for (int i = 0; i < valuescount; i++) {
printf("%s",values[i]);
}
}
// 釋放內存
ret = free_values(&values, &valuescount);
if (ret == 0) {
printf("values釋放內存成功!\n");
}
// 釋放資源
ret = release(&handle);
if (ret != 0) {
printf("env release error:%d\n",ret);
}
return 0;
}
測試配置文件:
username=root password=root123456 host=192.168.1.100 port=9090 connectionMax=200 version=1.0
測試結果:

源碼下載地址:git@github.com:xyang0917/RWAppProperites.git
最後更新:2017-04-03 12:56:25