http://www.leoox.com/?p=311
程序肯定需要一份配置文件,要不然,自己的程序不是“可配置”的,自己都不好意思往“高大上”靠攏。言歸正傳,以前自己寫代碼,配置文件的讀寫都是各式各樣的,有用過xml,有用過其他項目copy過來的。看開源代碼的時候,也是各式各樣的,比如redis的,Nginx等等。有時候就在想,配置文件的解析還真是麻煩,要自己處理一堆的字符串,有空的時候自己整理一下Nginx的源碼,復用Nginx的配置代碼,加強自己的代碼庫。但最近才發現,原來已經有一個很優秀的C/C++配置庫libconfig一直在等着我了。
認識libconfig
libconfig庫的官方網站在:http://www.hyperrealm.com/libconfig/
確實是非常優秀的C/C++配置庫,我們程序員完全可以從解析字符串的“苦力”中解脫出來。多復雜的配置項,都能滿足,來看看。
A configuration consists of a group of settings, which associate names with values. A value can be one of the following:
- A scalar value: integer, 64-bit integer, floating-point number, boolean, or string
- An array, which is a sequence of scalar values, all of which must have the same type
- A group, which is a collection of settings
- A list, which is a sequence of values of any type, including other lists
簡單直譯一下:
一個配置項,可以理解為我們最常見的key-value的形式。key就是你的配置的名字了。那優秀就優秀在value上了。value支持的類型有:
1、常見的數據類型:
整數(int):可以用10進制和16進制表示。0x打頭的數字libconfig會自動解析為16進制的數字。
64位整數(int64_t):在數字的后面加上L即可。
浮點數(float):個人不太喜歡用這個類型。
布爾數(bool):true或者false。不區分大小寫。
字符串(string):這個字符串非常強大。
a、支持轉義字符\\’, ‘\f’, ‘\n’, ‘\r’,‘\x’ and ‘\t’。
b、相鄰的字符串libconfig會自動拼接。這樣太常的內容,我們可以多行來寫,可讀性非常好。比如:
example = “hello world”; 等價於
example = “hello”
” world”;
【注意】
我們可以使用’=’,也可以使用’:’來作為賦值號。既然是C/C++程序員,還是使用’=’號看得舒服一些。
和C/C++的注釋一樣,/**/就是跨行的注釋。 //就是單行注釋。當然還支持腳本語言的注釋符號#,#也是單行注釋。但是特殊的是,如果注釋符在雙引號中使用,那就不再是注釋符了,libconfig會解析為正常的明文。
2、數組結構。和平常我們使用的數組是一樣一樣的,數組的各個元素都必須是相同的數據類型。
3、群組結構。這個可以理解為一個容器。這個容器里面,我們可以放置很多個配置項。當然這些配置項的value也可以繼續是群組。
4、列表結構。這個列表和我們C++常用的STL里的list結構可不太一樣。這個列表結構里面的元素不要求具備相同的數據類型,元素1是int,元素2可以是string,元素3可以是數組,元素4可以是一個群組,元素5可以是另一個列表。
可以說,正是因為value的多姿多彩,才給了我們程序員無限的發揮空間。通過群組結構和列表結構,我們可以很方便靈活的進行各種變態的配置讀取。除了讀取配置,可不要忘記了libconfig還有兩只手的哦:必要的時候,我們可以把內存里面的一些值,通過libconfig生成一份標准的配置文件。
體驗libconfig
動手用libconfig進行一個hello world的配置吧!把value支持的所有數據類型都用上,加深理解。
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
|
/* 這個叫Settings */
version = "1.0.0.0";
/* 這個叫Groups */
log = {
log_path = "../logs/sys.log"; /* 日志文件路徑 */
log_size = 1024000000L; /* 日志文件大小 */
log_level = 20000; /* 日志等級 */
};
/* 這個叫Lists */
// 業務服務器列表
server = (
{
addr = "10.1.88.1";
port = 9090;
},
{
addr = "10.1.88.2";
port = 9090;
},
{
addr = "10.1.88.3";
port = 9090;
}
);
// 測試配置
test = {
// 這個是數組結構。
uin = [10086L, 10087L, 10088L, 10089L]; /* 測試號碼 */
/* 測試服務器 */
server = {
addr = "10.1.99.1";
port = 9090;
};
};
|
值得說明的是,libconfig是通過路徑來讀取某一個配置的。比如log.log_path這個路徑對應的是log_path這個配置項,
server.[0].addr這個路徑對應的是業務服務器列表的第一個元素里面的addr這個配置項。
libconfig的代碼樣例
不寫一段hello world的代碼,是算不上真正接觸了libconfig的。libconfig提供了C和C++的API。先用C++來爽一下吧。
首先就是要下載安裝libconfig的庫。這個很簡單,到官網下載,然后./configure & make & make install就可以了。
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
|
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <libconfig.h++>
using namespace std;
using namespace libconfig;
/* g++ -o demo demo.cpp -I/home/leoox/local/libconfig-1.4.9/include/ /home/leoox/local/libconfig-1.4.9/lib/libconfig++.a */
int main(int argc, char** argv)
{
Config cfg;
/*
解析配置文件。
*/
try
{
cfg.readFile("example.conf");
}
catch(const FileIOException &fioex)
{
std::cerr << "I/O error while reading file." << std::endl;
return(EXIT_FAILURE);
}
catch(const ParseException &pex)
{
std::cerr << "Parse error at " << pex.getFile() << ":" << pex.getLine()
<< " - " << pex.getError() << std::endl;
return(EXIT_FAILURE);
}
/* 從配置文件中,得到version這個配置項的值。 */
try
{
string version = cfg.lookup("version");
cout << "version: " << version << endl << endl;
}
catch(const SettingNotFoundException &nfex)
{
cerr << "No 'version' setting in configuration file." << endl;
}
/* 從配置文件中,得到日志相關配置值 */
try
{
string log_path = cfg.lookup("log.log_path");
cout << "log_path: " << log_path << endl;
int64_t log_size = cfg.lookup("log.log_size");
cout << "log_size: " << log_size << endl;
int log_level = cfg.lookup("log.log_level");
cout << "log_level: " << log_level << endl << endl;
}
catch(const SettingNotFoundException &nfex)
{
cerr << "log setting mistake in configuration file." << endl;
}
try
{
const Setting &server = cfg.lookup("server");
int count = server.getLength();
cout << "server.count = " << count << endl;
for (int i = 0; i < count; i++)
{
string addr = "";
int port = 0;
if (!server[i].lookupValue("addr", addr)
|| !server[i].lookupValue("port", port))
{
cerr << "lookupValue error" << endl;
continue;
}
cout << "server[" << i << "] = " << addr << ":" << port << endl;
}
{
string addr = "";
int port = 0;
if (!cfg.lookupValue("server.[0].addr", addr)
|| !cfg.lookupValue("server.[0].port", port)) {
cerr << "lookupValue 'server.[0].addr' error" << endl;
}
else
cout << "server[0] = " << addr << ":" << port << endl << endl;
}
}
catch(const SettingNotFoundException &nfex)
{
cerr << "server setting mistake in configuration file." << endl;
}
try
{
const Setting& root = cfg.getRoot();
const Setting &uin = root["test"]["uin"];
int count = uin.getLength();
cout << "uin.count = " << count << endl;
const Setting &test = cfg.lookup("test");
const Setting &test2 = cfg.lookup("test.uin");
for (int i = 0 ; i < count; i++)
{
int64_t u = test["uin"][i];
int64_t uu = uin[i];
int64_t uuu = test2[i];
cout << "uin[" << i << "] = " << u << ", " << uu << ", " << uuu << endl;
}
const Setting &server = root["test"]["server"];
string addr = "";
int port = 0;
if (!server.lookupValue("addr", addr)
|| !server.lookupValue("port", port))
{
cerr << "test server lookupValue error" << endl;
}
else
cout << "test server = " << addr << ":" << port << endl << endl;
}
catch(const SettingNotFoundException &nfex)
{
cerr << "test setting mistake in configuration file." << endl;
}
return 0;
}
|
編譯和運行一下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
[leoox@Thrift config]$ g++ -o demo demo.cpp -I/home/leoox/local/libconfig-1.4.9/include/ /home/leoox/local/libconfig-1.4.9/lib/libconfig++.a
[leoox@Thrift config]$ ./demo
version: 1.0.0.0
log_path: ../logs/sys.log
log_size: 1024000000
log_level: 20000
server.count = 3
server[0] = 10.1.88.1:9090
server[1] = 10.1.88.2:9090
server[2] = 10.1.88.3:9090
server[0] = 10.1.88.1:9090
uin.count = 4
uin[0] = 10086, 10086, 10086
uin[1] = 10087, 10087, 10087
uin[2] = 10088, 10088, 10088
uin[3] = 10089, 10089, 10089
test server = 10.1.99.1:9090
|