2011-05-30 61 views
57

我有一个包含一些样本值就像一个ini文件:我试图加载这些值,并在我与升压应用程序进行打印如何解析ini文件与升压

[Section1] 
Value1 = 10 
Value2 = a_text_string 

但我不了解如何在C++中执行此操作。我在这个论坛搜索,以找到一些例子(我总是使用C,所以我不是很好的C++),但我只找到了关于如何从文件一次读取值的例子。

我需要加载一个单一的值,比如string = Section1.Value2,因为我不需要读取所有的值,但只是其中的一小部分。

我想加载单个值并将它们存储在变量中,以便在我的应用程序中使用它们。

可以用Boost做到这一点吗?

目前,我正在使用此代码:

#include <iostream> 
#include <string> 
#include <set> 
#include <sstream> 
#include <exception> 
#include <fstream> 
#include <boost/config.hpp> 
#include <boost/program_options/detail/config_file.hpp> 
#include <boost/program_options/parsers.hpp> 

namespace pod = boost::program_options::detail; 

int main() 
{ 
    std::ifstream s("file.ini"); 
    if(!s) 
    { 
     std::cerr<<"error"<<std::endl; 
     return 1; 
    } 

    std::set<std::string> options; 
    options.insert("Test.a"); 
    options.insert("Test.b"); 
    options.insert("Test.c"); 

    for (boost::program_options::detail::config_file_iterator i(s, options), e ; i != e; ++i) 
     std::cout << i->value[0] << std::endl; 
    } 

但这只是读入for循环中的所有值;相反,我只想在需要时读取单个值,并且不需要在文件中插入值,因为它已经写入了我在程序中需要的所有值。

回答

122

您还可以使用Boost.PropertyTree读取.ini文件:

#include <boost/property_tree/ptree.hpp> 
#include <boost/property_tree/ini_parser.hpp> 

... 

boost::property_tree::ptree pt; 
boost::property_tree::ini_parser::read_ini("config.ini", pt); 
std::cout << pt.get<std::string>("Section1.Value1") << std::endl; 
std::cout << pt.get<std::string>("Section1.Value2") << std::endl; 
+0

很好的答案! 这是我需要我的应用程序。 真的非常感谢! – 2011-05-30 12:55:23

+0

如果我不知道某些可用键的集合,但我仍想获取键=值对的完整列表,该怎么办?即你将如何重写你的程序而不使用“Section1.Value1”和“Section1.Value2”常量? – javapowered 2013-04-21 19:02:15

+0

更新:我发现这个问题http://stackoverflow.com/questions/11065938/boost-program-options-get-all-entries-in-section根据它是不可能的,没有编写自定义代码... – javapowered 2013-04-21 19:08:17

1

该文件需要解析,必须按顺序进行。因此,我只是读取整个文件,将所有值存储在某个集合中(mapunordered_map,可能使用pair<section, key>作为关键字或使用地图映射),并在需要时从中取出它们。

3

解析INI文件很容易由于其结构简单。使用AX我可以在几行写来解析部分,属性和评论:

auto trailing_spaces = *space & endl; 
auto section = '[' & r_alnumstr() & ']'; 
auto name = +(r_any() - '=' - endl - space); 
auto value = '"' & *("\\\"" | r_any() - '"') & '"' 
    | *(r_any() - trailing_spaces); 
auto property = *space & name & *space & '=' & *space 
    & value & trailing_spaces; 
auto comment = ';' & *(r_any() - endl) & endl; 
auto ini_file = *comment & *(section & *(prop_line | comment)) & r_end(); 

更详细的例子可以在Reference.pdf

找到关于不读整个文件,它可以在不同的完成方法。首先,INI格式的解析器至少需要前向迭代器,所以你不能使用流迭代器,因为它们是输入迭代器。你可以创建一个单独的类来与所需的迭代器进行流式处理(我在过去用滑动缓冲区写了一个这样的类)。您可以使用内存映射文件。或者,您可以使用动态缓冲区,从标准流中读取并提供给解析器,直到找到值。如果您不想拥有真正的解析器,并且不关心INI文件结构是否正确,那么您可以简单地在文件中搜索您的令牌。输入迭代器就足够了。

最后,我不确定避免阅读整个文件带来的好处。 INI文件通常非常小,并且由于硬盘驱动器和多个缓冲系统无论如何都会读取一个或多个扇区(即使您只需要一个字节),所以我怀疑部分读取文件会有任何性能改进(特别是反复做),可能是相反的。

+0

+1来引用看起来像C++ 11的有用解析库:http://www.gbresearch.com/axe/ – 2014-09-26 14:30:18