如何使用Boost解析ini文件

Posted

技术标签:

【中文标题】如何使用Boost解析ini文件【英文标题】:How to parse ini file with Boost 【发布时间】:2011-09-04 18:04:28 【问题描述】:

我有一个 ini 文件,其中包含一些示例值,例如:

[Section1]
Value1 = 10
Value2 = a_text_string

我正在尝试加载这些值并使用 Boost 在我的应用程序中打印它们,但我不明白如何在 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 循环中的所有值;相反,我只想在需要时读取单个值,并且不需要在文件中插入值,因为它已经写入了我在程序中需要的所有值。

【问题讨论】:

【参考方案1】:

需要解析文件,必须按顺序进行。所以我只需阅读整个文件,将所有值存储在某个集合中(mapunordered_map,可能使用pair&lt;section, key&gt; 作为键或使用地图映射)并在需要时从那里获取它们。

【讨论】:

【参考方案2】:

您还可以使用 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;

【讨论】:

如果我不知道某些可用键集,但我仍想获得键=值对的完整列表怎么办? IE。如果不使用“Section1.Value1”和“Section1.Value2”常量,你将如何重写你的程序? 更新:我发现了这个问题***.com/questions/11065938/…,根据它是不可能不编写自定义代码... @javapowered 你发现的问题是关于Boost.Program_options,而不是关于Boost.PropertyTree 解决了:***.com/questions/16135285/… Boost.PropertyTree 一直存在的问题是在节名和值名之间使用 , 。真正的 INI 文件支持包含“.”的部分名称和值名称。特点。更好的分隔符是 / 或 \。一个不可打印的字符,例如铃铛字符 (\007) 会更好。是否可以自定义此行为?【参考方案3】:

解析 INI 文件很容易,因为它们结构简单。使用 AX,我可以编写几行代码来解析部分、属性和 cmets:

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 文件通常很小,并且由于硬盘驱动器和多个缓冲系统无论如何都会读取一个或多个扇区(即使您只需要一个字节),所以我怀疑尝试部分读取文件是否会提高性能(尤其是重复做),可能相反。

【讨论】:

+1 参考看起来像是一个有用的 C++11 解析库:gbresearch.com/axe【参考方案4】:

我读过一篇关于使用 boost 方法进行 INI 解析的好文章,它被 Silviu Simen 称为 INI file reader using the spirit library。

这很简单。

【讨论】:

它也比较老了,使用的是“经典”风格的精神库。 +1 仍然

以上是关于如何使用Boost解析ini文件的主要内容,如果未能解决你的问题,请参考以下文章

如果将任何注释附加到键值,Boost 属性树 ini 解析会出错

使用 INI 文件提升属性树

当值部分不存在时使用 Boost 属性树读取 INI 文件

c ++如何使用boost xml解析器读取XML并存储在地图中

使用Boost.Python修复未解析的外部符号

如何使用 Boost ptree C++ 解析其值中包含 HTML 标记的 XML