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 |