一、libconfig是什么
Libconfig是一个结构化的配置文件库,它可以定义一些配置文件,例如test.cfg . 它比xml可读性更好,而且更简洁。而且不像xml,它是 type-aware类型自我感知的,因此不需要做string parsing 。
Libconfig 是用于读取、操作和写入结构化配置文件的库。 该库具有完全可重入的解析器,并包括 C 和 C++ 编程语言的绑定。该库可在现代 POSIX 兼容系统上运行,例如 Linux、Solaris 和 Mac OS X (Darwin),以及 Microsoft Windows 2000/XP 及更高版本(使用 Microsoft Visual Studio 2005 或更高版本,或 GNU 工具链通过 MinGW 环境)。
二、libconfig的解析方式
一个配置由一组setting构成,setting由名字(name)关联,并有相应的值(value)。一个值(value)可以是以下任意一种类型:
标量值(scalarvalue):整型、64位整型、浮点数、布尔值或者字符串
数组(array):一组标量值的序列,所有的标量值必须为同一类型
群组(group):多个setting的集合
列表(list):一组值(value)的序列,各个值可(value)以分别为不同的类型,其他的列表也可以包含其中。
包含在配置中的某个setting可以用path来唯一定义,path用点号分隔连接多个名字(name),由最顶层的群组(group)开始,到setting自身结束。path中的每个名字都是一个setting的名字;如果这个setting没有名字,那是因为它是数组(array)或列表(list)中的一个元素。用方括号包含一个整型索引值可以用来表示它的名字。
值的数据类型由值本身的格式确定。如果值用双引号括起来,则将其视为字符串。如果它看起来像一个整数或浮点数,则按原样处理。如果它是值 TRUE、true、FALSE 或 false(或这些标记的任何其他大小写混合版本,例如 True 或 FaLsE)之一,则将其视为布尔值。如果它由括在方括号中的逗号分隔值列表组成,则将其视为数组。如果它由括在括号中的逗号分隔值列表组成,则将其视为列表。任何不满足这些条件的值都被视为无效并导致解析错误。所有名称都区分大小写。它们只能由字母数字字符、破折号 (‘-’)、下划线 (‘_’) 和星号 (‘*’) 组成,并且必须以字母或星号开头。不允许使用其他字符。
在 C 和 C++ 中,整数、64 位整数、浮点数和字符串值分别映射到本机类型 int、long long、double 和 const char *。 boolean 类型在 C 中映射为 int,在 C++ 中映射为 bool。以下部分更详细地描述了配置文件语法的元素:
- setting
一个setting的格式如下:
name= value;或者name: value;结尾的分号是必须要有的,空白字符会被忽略;value可以是标量值、数组、群组或者列表。
- 群组(group)
一个群组的格式如下:{setting1,setting2, …},一个群组可以包含任意个setting,但是在群组中,每个setting的名字必须是唯一的。
- 数组(array)
一个数组的格式如下:[value,value, …],一个数组可以有零个或者多个元素,但是每个元素都必须是相同类型的标量值。
- 列表(list)
一个列表的格式如下:(value,value, …),一个列表可以有零个或者多个元素,而且每个元素可以分别是标量值、数组、群组或其他列表。
- 整型值
整型值(int)可以用两种方式表示:十进制数,由0-9组成,并且可以带+或-;十六进制数,0x打头并且用十六进制数表示。
- 64位整型值
64位整型值(longlong)表示方法和整型值基本一致,但是需要在最后加上L来表明它是一个64位整型值。比如0L表示一个64位的0值。
- 浮点值
浮点值由一个十进制数,可以带正负符号,然后带上一个可选的指数。这个可选的指数又由字母E或者e加上一个可选的正负符号再加上具体的数字。
- 布尔值
布尔值的取值只能是true和false,包括另外大小写混合的写法,比如tRue或FaLSe。
- 字符串
字符串是由双引号引起来的任意文本。字符串里的双引号由转义符\”替代,其他的转义符比如\\、\f、\r、\n、\t都可以被辨认,并且与通常的理解一致。
另外,转义符\x也被支持。它后面必须跟上刚好两个十六进制数,用来表示8位的ASCII值,比如\xFF表示值为0xFF的ASCII码。
其他的转义符都不被支持。
相邻的两个字符串会被自动连接,就像C的编码规则一样。在把一个很长得字符串格式化为很短的字符串的时候,就会很有用。比如,下面三种写法的字符串都是等价的。
"Thequickbrownfoxjumpedoverthelazydog."
"Thequickbrownfox"
"jumpedoverthelazydog."
"Thequick"/*注释*/"brownfox"//其他注释
"jumpedoverthelazydog."
- 注释
在配置文件中允许三种类型的注释
脚本风格的注释:从#开始到行尾的内容都为注释。
C风格的注释:/*和*/之间的内容,即使是跨行的,都被认为是注释。
C++风格的注释:从//开始到行尾的内容都被认为是注释。
如预料的一样,注释符在双引号字符串中出现,会被认为是字符串的文本而不是注释符。
在读取配置的时候,注释内容会被忽略,它们不会被认为是配置的一部分。因此,如果配置回写到文件中,原配置文件中的一些注释会丢失。
- 包含指令
一个配置文件可能包含了另外一个配置文件的内容,这时就要用到包含指令。这个指令产生的效果就是在包含点内联了那个文件的内容。
一个包含指令必须出现在它所在的那一行中,格式如下:
@include“filename”
文件名中反斜杠和双引号必须用转义符\\和\”来替代。
举例说明,观察下面两个配置文件
#file:quote.cfg quote="Criticismmaynotbeagreeable,butitisnecessary." "Itfulfilsthesamefunctionaspaininthehuman" "body.Itcallsattentiontoanunhealthystateof" "things.\n" "\t--WinstonChurchill"; |
#file:test.cfg info:{ name="WinstonChurchill"; @include"quote.cfg" country="UK"; }; |
包含文件最大只能嵌套10层,突破这个限制会产生一个分析错误。
与注释类似,包含指令也不是配置文件句法的一部分。包含指令在配置文件被分析之前就已经被处理了。因此,当配置回写回文件的时候,包含指令不会被保留。目前还不支持让程序把包含指令插入到配置文件中。
三、使用libconfig注意事项
1. C++API 头文件 #include <libconfig.h++> ,命名空间:using namespace libconfig;
2.多线程使用问题:
(1)libconfig是完全可重入的,库中函数不使用全局变量和不保持成功调用间的状态。所以两个独立配置文件在两个不同线程间并发操作可以是安全的;
(2)libconfig是线程不安全,libconfig不考虑系统线程模型。所以一个配置文件的实例被多个线程获取,必须使用同步机制(例如读写锁或互斥锁)来保护。
(3)libconfig不是异步安全,不能在信号句柄中调用
(4)libconfig不能保证取消安全。因为它不知道主机系统的线程模型,库不包含任何线程取消点。在大多数情况下这将不是多线程程序的问题。但是,请注意一些库中的例程(即那些从/到文件读取/写入配置的程序)流)使用可能会阻止的C库例程执行I/O;是否这些C库例程是取消安全的,取决于主机系统。
3.C++API
C++API使用Config类和Setting类,因为不提供公有的copy constructor or assignment operator,所以在函数参数中传递时使用引用或指针方式
四、libconfig常用API
1、Method on Config: void readFile (const char * filename)
readFile() 方法从名为 “filename” 的文件中读取并解析配置。 如果发生解析错误,则抛出 ParseException。 如果无法读取文件,则抛出 FileIOException。
2、Method on Config: void writeFile (const char * filename)
writeFile() 方法将配置写入名为 “filename” 的文件。 如果无法写入文件,则会引发 FileIOException。
3、Method on Config: Setting & lookup (const std::string &path)
Method on Config: Setting & lookup (const char * path)
这两个方法定位由路径指定的Setting。 如果未找到请求的Setting,则抛出 SettingNotFoundException。返回值为Setting对应的value。
4、Method on Config: Setting & getRoot ()
此方法返回Setting的根设置,是一个Group。
5、Method on Config: bool lookupValue (const char *path, bool &value)
Method on Config: bool lookupValue (const std::string &path, bool &value)
Method on Config: bool lookupValue (const char *path, int &value)
Method on Config: bool lookupValue (const std::string &path, int &value)
Method on Config: bool lookupValue (const char *path, unsigned int &value)
Method on Config: bool lookupValue (const std::string &path, unsigned int &value)
Method on Config: bool lookupValue (const char *path, long long &value)
Method on Config: bool lookupValue (const std::string &path, long long &value)
Method on Config: bool lookupValue (const char *path, float &value)
Method on Config: bool lookupValue (const std::string &path, float &value)
Method on Config: bool lookupValue (const char *path, double &value)
Method on Config: bool lookupValue (const std::string &path, double &value)
Method on Config: bool lookupValue (const char *path, const char *&value)
Method on Config: bool lookupValue (const std::string &path, const char *&value)
Method on Config: bool lookupValue (const char *path, std::string &value)
Method on Config: bool lookupValue (const std::string &path, std::string &value)
这些方法是使用给定path查找Setting值的便捷方法。 如果找到该Setting并且是适当的类型,则将该值存储在 value 中并且该方法返回 true。 否则, value 保持不变并且该方法返回 false。 这些方法不会抛出异常。
五、Linux下 C/C++ libconfig安装及配置
libconfig下载地址:https://hyperrealm.github.io/libconfig/
1、解压并安装:
tar xzvf libconfig-1.7.2.tar.gz
cd libconfig-1.7.2
sudo ./configure
sudo make
sudo make check
sudo make install
2、配置环境变量,libconfig默认安装在/usr/local/lib下,将此路径添加到path中
export LD_LIBRARY_PATH=/usr/local/lib //配置环境变量
sudo ldconfig -V //查看是否安装
3、测试
1)测试C版本
cd examples/c/
gcc example1.c -o example1 -lconfig
./example1
2)测试C++版本
cd examples/c++/
g++ example1.cpp -lconfig++ -o example1
./example1