參考 Java Properties 類設計,實現純 C 語言的配置文件讀寫庫。支援 key=value 格式,提供完整 CRUD 接口、鏈表內存管理、文件持久化、跨平台編譯 (含 C++ 混編護衛)。
// 單個配置項節點
typedef struct Properties {
char *key;
char *value;
struct Properties *pNext;
} Properties;
// 環境句柄 (不透明指針)
typedef struct PROPS_HANDLE {
Properties *pHead; // 虛擬頭節點
char *filepath; // 配置文件路徑
} PROPS_HANDLE;
| 函數 | 功能 | 返回值 |
|---|---|---|
init(filepath, &handle) | 初始化,解析文件建立鏈表 | 0 成功,非 0 錯誤碼 |
getValue(handle, key, value) | 查詢鍵值 | 0 找到,-2 未找到 |
setValue(handle, key, value) | 修改現有鍵值並持久化 | 0 成功,-2 鍵不存在 |
add(handle, key, value) | 新增鍵值 (存在則轉修改) | 0 成功 |
del(handle, key) | 刪除鍵值並持久化 | 0 成功,-2 鍵不存在 |
getKeys(handle, &keys, &count) | 獲取所有鍵 (需調用 free_keys 釋放) | 0 成功 |
getValues(handle, &values, &count) | 獲取所有值 (需調用 free_values 釋放) | 0 成功 |
getCount(handle, &count) | 獲取配置項總數 | 0 成功 |
release(&handle) | 釋放所有資源 (鏈表、路徑、句柄) | 0 成功 |
fgets 讀取,strstr 尋找 = 分隔鍵值trimeSpace 去除首尾空格malloc + strcpy)
static int saveConfig(const char *filepath, Properties *head) {
FILE *fp = fopen(filepath, "w");
Properties *p = head->pNext;
while (p) {
fprintf(fp, "%s=%s", p->key, p->value); // value 已含換行
p = p->pNext;
}
fclose(fp);
return 0;
}
注意:setValue/add/del 修改鏈表後立即全量覆寫文件,保證內存與磁盤一致性。生產環境建議寫臨時文件再 rename 替換,實現原子更新。
release 遞歸釋放鏈表每個節點的 key、value、節點本身、文件路徑、句柄free_keys/free_values 僅釋放指針陣列 (char**),不釋放字串內容 (字串歸鏈表節點所有)char***),方便函數修改調用者指針並歸零防野指針
// props.txt 初始內容
username=root
password=root123456
host=192.168.1.100
port=9090
connectionMax=200
version=1.0
// main.c 測試流程
init("props.txt", &handle);
getValue(handle, "host", buf); // 192.168.1.100
setValue(handle, "version", "1.2.3"); // 修改
add(handle, "pool_connection_countxx", "2000"); // 新增
del(handle, "connectionMax"); // 刪除
getKeys(handle, &keys, &count); // 遍歷所有鍵
getValues(handle, &vals, &count); // 遍歷所有值
release(&handle); // 完整釋放

[section] key=value 結構 (類似 INI)getInt/getBool/getFloat 封裝 atoi/atofGitHub: git@github.com:xyang0917/RWAppProperites.git