用C ++创build一个简单的configuration文件和parsing器

我正在尝试创build一个看起来像这样的简单configuration文件

url = http://mysite.com file = main.exe true = 0 

当程序运行时,我希望将configuration设置加载到下面列出的程序variables中。

 string url, file; bool true_false; 

我已经做了一些研究, 这个链接似乎有帮助(核子的post),但我似乎无法得到它的工作,这是我的一部分太复杂了。 有没有一个简单的方法来做到这一点? 我可以使用ifstream加载文件,但是尽可能的我自己。 谢谢!

一般来说,在两个阶段中parsing这些典型的configuration文件是最简单的:首先读取这些行,然后逐一parsing这些文件。
在C ++中,可以使用std::getline()从一个stream中读取行。 虽然默认情况下它会读取到下一个'\n' (它将消耗,但不返回),您也可以传递给它一些其他的分隔符,这使得它是一个很好的候选人阅读最多的一些字符,就像在你的例子中。

为简单起见,下面假设= 被空白包围。 如果要在这些位置允许空格,则必须在读取值之前策略性地放置is >> std::ws ,并从键中移除末尾的空格。 然而,IMO在语法上增加了一点灵活性,这对configuration文件读取器来说是不值得的。

 const char config[] = "url=http://example.com\n" "file=main.exe\n" "true=0"; std::istringstream is_file(config); std::string line; while( std::getline(is_file, line) ) { std::istringstream is_line(line); std::string key; if( std::getline(is_line, key, '=') ) { std::string value; if( std::getline(is_line, value) ) store_line(key, value); } } 

(添加error handling作为练习留给读者。)

正如其他人所指出的那样,使用现有的configuration文件parsing器库可能会less一些工作,而不是重新发明轮子。

例如,如果您决定使用Config4Cpp库(我维护它),那么您的configuration文件语法将略有不同(将值放在双引号内,并用分号终止赋值语句),如下例所示:

 # File: someFile.cfg url = "http://mysite.com"; file = "main.exe"; true_false = "true"; 

以下程序parsing上述configuration文件,将所需的值复制到variables并打印出来:

 #include <config4cpp/Configuration.h> #include <iostream> using namespace config4cpp; using namespace std; int main(int argc, char ** argv) { Configuration * cfg = Configuration::create(); const char * scope = ""; const char * configFile = "someFile.cfg"; const char * url; const char * file; bool true_false; try { cfg->parse(configFile); url = cfg->lookupString(scope, "url"); file = cfg->lookupString(scope, "file"); true_false = cfg->lookupBoolean(scope, "true_false"); } catch(const ConfigurationException & ex) { cerr << ex.c_str() << endl; cfg->destroy(); return 1; } cout << "url=" << url << "; file=" << file << "; true_false=" << true_false << endl; cfg->destroy(); return 0; } 

Config4Cpp 网站提供了全面的文档,但只需阅读“入门指南”的第2章和第3章就足以满足您的需求。

一个天真的做法可能是这样的:

 #include <map> #include <sstream> #include <stdexcept> #include <string> std::map<std::string, std::string> options; // global? void parse(std::istream & cfgfile) { for (std::string line; std::getline(cfgfile, line); ) { std::istringstream iss(line); std::string id, eq, val; bool error = false; if (!(iss >> id)) { error = true; } else if (id[0] == '#') { continue; } else if (!(iss >> eq >> val >> std::ws) || eq != "=" || iss.get() != EOF) { error = true; } if (error) { // do something appropriate: throw, skip, warn, etc. } else { options[id] = val; } } } 

现在,您可以从程序中的任何位置访问全局options映射中的每个选项值。 如果你想要可塑性,你可以使映射types为boost::variant

libconfig是非常容易的,更好的是,它使用伪json符号来提高可读性。

易于在Ubuntu上安装: sudo apt-get install libconfig++8-dev

并链接: -lconfig++

为什么不尝试一些简单的和人类可读的,如JSON(或XML)?

对于C ++来说,有许多预制的JSON(或XML)的开源实现 – 我会使用其中的一个。

如果你想要更多的“二进制” – 尝试BJSON或BSON 🙂

我最近search了我的项目的configurationparsing库,发现这些库:

如何将您的configuration格式化为JSON,并使用类似jsoncpp的库?

例如

 {"url": "http://mysite dot com", "file": "main.exe", "true": 0} 

然后,您可以将其读入命名variables,甚至将其全部存储在std :: map等中。后者意味着您可以添加选项,而无需更改和重新编译configurationparsing器。

这里是一个简单的工作,在configuration文件中的'='符号和数据之间的空白。 从'='符号之后的位置分配给istringstream,并从中读取时,忽略任何前导空格。

注意:在循环中使用istringstream时,请确保在为其分配新string之前调用clear()。

 //config.txt //Input name = image1.png //Num. of rows = 100 //Num. of cols = 150 std::string ipName; int nR, nC; std::ifstream fin("config.txt"); std::string line; std::istringstream sin; while (std::getline(fin, line)) { sin.str(line.substr(line.find("=")+1)); if (line.find("Input name") != std::string::npos) { std::cout<<"Input name "<<sin.str()<<std::endl; sin >> ipName; } else if (line.find("Num. of rows") != std::string::npos) { sin >> nR; } else if (line.find("Num. of cols") != std::string::npos) { sin >> nC; } sin.clear(); }