配置文件很重要,INI 太弱,XML 太繁复,Linux *.conf 很酷。
找了好几种相关的类库,发觉还是 最强大最好用,相关细节可参考 。
源中的版本是 1.3.2-1,也可以去官方文章下载最新版本。
$ sudo apt-get install libconfig8 libconfig8-dev
|
完全类脚本化的配置语法,支持注释、包含、简单配置、数组、列表以及非常像类的组。
test.conf
# Example application configuration file
title = "Test Application"; // scalar value
version = 1; // int, int64, float, bool, string
app: // group
{
user:
{
name = "Q.yuhen";
code = "xxx-xxx-xxx";
tags = ["t1", "t2", "t3"]; // array
data = ( "Hello", 1234 ); // list
};
};
|
1. Path
直接用多级路径读取目标值,这是最简单的做法。注意区分参数中 path 和 name 的区别,后者无法使用路径。
int config_lookup_int (const config_t * config, const char * path, int * value)
int config_lookup_int64 (const config_t * config, const char * path, long long * value)
int config_lookup_float (const config_t * config, const char * path, double * value)
int config_lookup_bool (const config_t * config, const char * path, int * value)
int config_lookup_string (const config_t * config, const char * path, const char ** value)
|
我们试试看。
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <libconfig.h>
void scalar(config_t* conf)
{
char* title;
config_lookup_string(conf, "title", &title);
printf("title = %s;n", title);
int version;
config_lookup_int(conf, "version", &version);
printf("version = %d;n", version);
char* user_name;
config_lookup_string(conf, "app.user.name", &user_name);
printf("app.user.name = %s;n", user_name);
char* tag;
config_lookup_string(conf, "app.user.tags.[2]", &tag);
printf("app.user.tags[2] = %s;n", tag);
int data;
config_lookup_int(conf, "app.user.data.[1]", &data);
printf("app.user.data.[1] = %d;n", data);
}
int main(int argc, char* argv[])
{
config_t* conf = NULL;
config_init(conf);
config_read_file(conf, "test.conf");
scalar(conf);
config_destroy(conf);
return EXIT_SUCCESS;
}
|
输出:
title = Test Application;
version = 1;
app.user.name = Q.yuhen;
app.user.tags[2] = t3;
app.user.data.[1] = 1234;
|
2. Config_Setting
所有的 Group 和其 Member 都是 Config_Setting,我们可以用 config_lookup() 找出目标后,然后使用 Name 读取。
config_setting_t * config_lookup (const config_t * config, const char * path)
int config_setting_lookup_int (const config_setting_t * setting, const char * name, int * value)
int config_setting_lookup_int64 (const config_setting_t * setting, const char * name, long long * value)
int config_setting_lookup_float (const config_setting_t * setting, const char * name, double * value)
int config_setting_lookup_bool (const config_setting_t * setting, const char * name, int * value)
int config_setting_lookup_string (const config_setting_t * setting, const char * name, const char ** value)
|
注意 config_setting_lookup_xxx() 只能使用 Member Name,而不是 Path。
void group(config_t* conf)
{
config_setting_t* user = config_lookup(conf, "app.user");
char* code;
config_setting_lookup_string(user, "code", &code);
printf("user.code = %s;n", code);
}
|
利用相关的函数,我们还可以遍历 Array/List 的所有 Element。
void group(config_t* conf)
{ config_setting_t* user = config_lookup(conf, "app.user");
config_setting_t* tags = config_setting_get_member(user, "tags");
int count = config_setting_length(tags);
int i;
for (i = 0; i < count; i++)
{
printf("user.tags[%d] = %s;n", i, config_setting_get_string_elem(tags, i));
}
}
|
输出:
user.tags[0] = t1;
user.tags[1] = t2;
user.tags[2] = t3;
|
当然,我们也可以用 config_lookup() 直接找到 app.user.tags,然后遍历。
void group(config_t* conf)
{
config_setting_t* tags = config_lookup(conf, "app.user.tags");
int count = config_setting_length(tags);
int i;
for (i = 0; i < count; i++)
{
printf("user.tags[%d] = %s;n", i, config_setting_get_string_elem(tags, i));
}
printf("-----------------------n");
config_setting_t* code = config_lookup(conf, "app.user.code");
printf("user.code = %s;n", config_setting_get_string(code));
}
|
输出:
user.tags[0] = t1;
user.tags[1] = t2;
user.tags[2] = t3;
-----------------------
user.code = xxx-xxx-xxx;
|
上面的例子中,我们还可以直接用 lookup() 查找简单配置 app.user.code,然后用相关方法返回值,无需再次提供 Name。
int config_setting_get_int (const config_setting_t * setting)
long long config_setting_get_int64 (const config_setting_t * setting)
double config_setting_get_float (const config_setting_t * setting)
int config_setting_get_bool (const config_setting_t * setting)
const char * config_setting_get_string (const config_setting_t * setting)
|
Array/List 的内容可以是 Group,我们可以用 config_setting_get_elem() 获取指定序号的元素后继续操作。
config_setting_t * config_setting_get_member (config_setting_t * setting, const char * name)
config_setting_t * config_setting_get_elem (const config_setting_t * setting, unsigned int idx)
|
3. Write
配置文件吗,增删改操作都要全乎。
int config_setting_set_int (config_setting_t * setting, int value)
int config_setting_set_int64 (config_setting_t * setting, long long value)
int config_setting_set_float (config_setting_t * setting, double value)
int config_setting_set_bool (config_setting_t * setting, int value)
int config_setting_set_string (config_setting_t * setting, const char * value)
config_setting_t * config_setting_set_int_elem (config_setting_t * setting, int idx, int value)
config_setting_t * config_setting_set_int64_elem (config_setting_t * setting, int idx, long long value)
config_setting_t * config_setting_set_float_elem (config_setting_t * setting, int idx, double value)
config_setting_t * config_setting_set_bool_elem (config_setting_t * setting, int idx, int value)
config_setting_t * config_setting_set_string_elem (config_setting_t * setting, int idx, const char * value)
config_setting_t * config_setting_add (config_setting_t * parent, const char * name, int type)
int config_setting_remove (config_setting_t * parent, const char * name)
int config_setting_remove_elem (config_setting_t * parent, unsigned int idx)
const char * config_setting_name (const config_setting_t * setting)
|
为了方便查看,我直接 "保存" 到 stdout 了。
void write(config_t* conf)
{
config_setting_t* user = config_lookup(conf, "app.user");
config_setting_t* name = config_setting_get_member(user, "name");
config_setting_t* tags = config_setting_get_member(user, "tags");
config_setting_t* data = config_setting_get_member(user, "data");
/* ----------------- Add ------------------- */
config_setting_t* comment = config_setting_add(user, "comment", CONFIG_TYPE_STRING);
config_setting_set_string(comment, "test...");
/* ----------------- Remove ---------------- */
config_setting_remove(user, "code");
config_setting_remove_elem(tags, 1);
/* ----------------- Set ------------------- */
config_setting_set_string(name, "Rainsoft");
config_setting_set_string_elem(data, 0, "Ubuntu");
/* ----------------- Write ----------------- */
config_write(conf, stdout);
}
|
输出:
title = "Test Application";
version = 1;
app :
{
user :
{
name = "Rainsoft";
tags = [ "t1", "t3" ];
data = ( "Ubuntu", 1234 );
comment = "test...";
};
};
|
4. Q&A
(1) 调用 config_destroy(conf) 后,其分配的字符串会被全部释放,因此得自己注意 strcpy / strdup。
(2) 官方文档中标明了 "Libconfig is not thread-safe","Libconfig is not async-safe" ……
(3) 似乎 Array/List 必须是 Group Member,不知道是不是版本的问题。
阅读(681) | 评论(0) | 转发(0) |