当前位置:主页 > c/c++教程 > C++ Boost PropertyTree

C++ Boost PropertyTree示例超详细讲解

发布:2023-03-12 09:00:01 59


为找教程的网友们整理了相关的编程文章,网友农朋义根据主题投稿了本篇教程内容,涉及到C++、Boost、PropertyTree、C++、Boost、PropertyTree示例、C++ Boost PropertyTree相关内容,已被817网友关注,相关难点技巧可以阅读下方的电子资料。

C++ Boost PropertyTree

一、提要

借助类 boost::property_tree::ptree,Boost.PropertyTree 提供了一个树结构来存储键/值对。树形结构意味着一个树干存在许多分支,其中有许多树枝。文件系统是树结构的一个很好的例子。文件系统有一个带有子目录的根目录,这些子目录本身可以有子目录等等。

二、应用示例

要使用 boost::property_tree::ptree,请包含头文件 boost/property_tree/ptree.hpp。这是一个主头文件,因此 Boost.PropertyTree 不需要包含其他头文件。

示例 25.1。访问 boost::property_tree::ptree 中的数据

#include 
#include 
using boost::property_tree::ptree;
int main()
{
  ptree pt;
  pt.put("C:.Windows.System", "20 files");
  ptree &c = pt.get_child("C:");
  ptree &windows = c.get_child("Windows");
  ptree &system = windows.get_child("System");
  std::cout << system.get_value() << '\n';
}

Example25.1

example25.1 使用 boost::property_tree::ptree 来存储目录的路径。这是通过调用 put() 来完成的。此成员函数需要两个参数,因为 boost::property_tree::ptree 是一个保存键/值对的树结构。树不仅由树枝和树枝组成,还必须为每个树枝和树枝分配一个值。在示例 25.1 中,该值为“20 个文件”。

传递给 put() 的第一个参数更有趣。它是一个目录的路径。但是,它不使用反斜杠,这是 Windows 上常见的路径分隔符。它使用点。

您需要使用点,因为它是 Boost.PropertyTree 期望的键的分隔符。参数“C:.Windows.System”告诉 pt 创建一个名为 C: 的分支,其中一个名为 Windows 的分支具有另一个名为 System 的分支。点创建分支的嵌套结构。如果“C:\Windows\System”作为参数传递,pt 将只有一个名为 C:\Windows\System 的分支。

调用 put() 后,访问 pt 以读取存储的值“20 个文件”并将其写入标准输出。这是通过从一个分支跳转到另一个分支 - 或从一个目录跳转到另一个目录来完成的。

要访问子分支,您可以调用 get_child(),它会返回对与调用 get_child() 相同类型的对象的引用。在示例 25.1 中,这是对 boost::property_tree::ptree 的引用。因为每个分支都可以有子分支,并且由于高低分支之间没有结构差异,所以使用相同的类型。

第三次调用 get_child() 检索 boost::property_tree::ptree,它表示目录 System。调用 get_value() 以读取在示例开头使用 put() 存储的值。

请注意,get_value() 是一个函数模板。您将返回值的类型作为模板参数传递。这样 get_value() 可以进行自动类型转换。

示例 25.2。访问 basic_ptree 中的数据

#include 
#include 
#include 
int main()
{
  typedef boost::property_tree::basic_ptree ptree;
  ptree pt;
  pt.put(ptree::path_type{"C:\\Windows\\System", '\\'}, 20);
  pt.put(ptree::path_type{"C:\\Windows\\Cursors", '\\'}, 50);
  ptree &windows = pt.get_child(ptree::path_type{"C:\\Windows", '\\'});
  int files = 0;
  for (const std::pair &p : windows)
    files += p.second.get_value();
  std::cout << files << '\n';
}

与示例 25.1 相比,示例 25.2 有两个变化。这些更改是为了更轻松地保存目录路径和目录中的文件数量。首先,路径在传递给 put() 时使用反斜杠作为分隔符。其次,文件的数量存储为 int。

默认情况下,Boost.PropertyTree 使用点作为键的分隔符。如果您需要使用其他字符(例如反斜杠)作为分隔符,则不要将键作为字符串传递给 put()。相反,您将其包装在 boost::property_tree::ptree::path_type 类型的对象中。这个类的构造函数依赖于 boost::property_tree::ptree,它的第一个参数是键,第二个参数是分隔符。这样,您可以使用 C:\Windows\System 等路径,如示例 25.2 所示,而无需将反斜杠替换为点。

boost::property_tree::ptree 基于类模板 boost::property_tree::basic_ptree。因为键和值通常是字符串,所以 boost::property_tree::ptree 是预定义的。但是,您可以将 boost::property_tree::basic_ptree 用于键和值的不同类型。示例 25.2 中的树使用 int 来存储目录中的文件数,而不是字符串。

boost::property_tree::ptree 提供成员函数 begin() 和 end()。但是,boost::property_tree::ptree 只允许您在一个级别上迭代分支。示例 25.2 遍历 C:\Windows 的子目录。您无法让迭代器遍历所有级别的所有分支。

示例 25.2 中的 for 循环读取 C:\Windows 的所有子目录中的文件数以计算总数。因此,该示例显示 70。该示例不直接访问 ptree 类型的对象。相反,它迭代类型为 std::pair 的元素。 first 包含当前分支的键。即示例 25.2 中的系统和游标。第二个提供对 ptree 类型对象的访问,它表示可能的子目录。在示例中,仅读取分配给 System 和 Cursors 的值。如示例 25.1,调用成员函数 get_value()。

boost::property_tree::ptree 只存储当前分支的值,而不是它的键。您可以使用 get_value() 获取值,但没有获取密钥的成员函数。密钥存储在 boost::property_tree::ptree 上一级。这也解释了为什么 for 循环会迭代 std::pair 类型的元素。

示例 25.3。使用翻译器访问数据

#include 
#include 
#include 
#include 
struct string_to_int_translator
{
  typedef std::string internal_type;
  typedef int external_type;
  boost::optional get_value(const std::string &s)
  {
    char *c;
    long l = std::strtol(s.c_str(), &c, 10);
    return boost::make_optional(c != s.c_str(), static_cast(l));
  }
};
int main()
{
  typedef boost::property_tree::iptree ptree;
  ptree pt;
  pt.put(ptree::path_type{"C:\\Windows\\System", '\\'}, "20 files");
  pt.put(ptree::path_type{"C:\\Windows\\Cursors", '\\'}, "50 files");
  string_to_int_translator tr;
  int files =
    pt.get(ptree::path_type{"c:\\windows\\system", '\\'}, tr) +
    pt.get(ptree::path_type{"c:\\windows\\cursors", '\\'}, tr);
  std::cout << files << '\n';
}

Example25.3

示例 25.3 与 boost::property_tree::iptree 一起使用来自 Boost.PropertyTree 的另一个预定义树。通常,此类型的行为类似于 boost::property_tree::ptree。唯一的区别是 boost::property_tree::iptree 不区分大小写。例如,使用 C:\Windows\System 键存储的值可以用 c:\windows\system 读取。

与示例 25.1 不同,get_child() 不会被多次调用来访问子分支。正如 put() 可用于将值直接存储在子分支中一样,子分支中的值也可以使用 get() 读取。键的定义方式相同——例如使用 boost::property_tree::iptree::path_type。

与 get_value() 一样,get() 是一个函数模板。您必须将返回值的类型作为模板参数传递。 Boost.PropertyTree 进行自动类型转换。

为了转换类型,Boost.PropertyTree 使用翻译器。该库提供了一些开箱即用的翻译器,它们基于流并且可以自动转换类型。

示例 25.3 与 boost::property_tree::iptree 一起使用来自 Boost.PropertyTree 的另一个预定义树。通常,此类型的行为类似于 boost::property_tree::ptree。唯一的区别是 boost::property_tree::iptree 不区分大小写。例如,使用 C:\Windows\System 键存储的值可以用 c:\windows\system 读取。

与示例 25.1 不同,get_child() 不会被多次调用来访问子分支。正如 put() 可用于将值直接存储在子分支中一样,子分支中的值也可以使用 get() 读取。键的定义方式相同——例如使用 boost::property_tree::iptree::path_type。

与 get_value() 一样,get() 是一个函数模板。您必须将返回值的类型作为模板参数传递。 Boost.PropertyTree 进行自动类型转换。

为了转换类型,Boost.PropertyTree 使用翻译器。该库提供了一些开箱即用的翻译器,它们基于流并且可以自动转换类型。

Example25.3

#include 
#include 
#include 
using boost::property_tree::ptree;
int main()
{
  ptree pt;
  pt.put("C:.Windows.System", "20 files");
  boost::optional c = pt.get_optional("C:");
  std::cout << std::boolalpha << c.is_initialized() << '\n';
  pt.put_child("D:.Program Files", ptree{"50 files"});
  pt.add_child("D:.Program Files", ptree{"60 files"});
  ptree d = pt.get_child("D:");
  for (const std::pair &p : d)
    std::cout << p.second.get_value() << '\n';
  boost::optional e = pt.get_child_optional("E:");
  std::cout << e.is_initialized() << '\n';
}

示例 25.3 定义了转换器 string_to_int_translator,它将 std::string 类型的值转换为 int。翻译器作为附加参数传递给 get()。因为翻译器只是用来阅读的,所以它只定义了一个成员函数,get_value()。如果您也想使用翻译器进行写作,那么您需要定义一个成员函数 put_value(),然后将翻译器作为附加参数传递给 put()。

get_value() 返回 pt 中使用的类型的值。但是,由于类型转换并不总是成功,因此使用了 boost::optional。如果示例 25.3 中存储的值无法使用 std::strtol() 转换为 int,则将返回 boost::optional 类型的空对象。

请注意,翻译人员还必须定义 internal_type 和 external_type 两种类型。如果需要在存储数据时进行类型转换,请定义类似于 get_value() 的 put_value()。

如果您修改示例 25.3 以存储值“20”而不是值“20 个文件”,则可以调用 get_value() 而无需传递翻译器。 Boost.PropertyTree 提供的翻译器可以将 std::string 转换为 int。但是,只有在可以转换整个字符串时,类型转换才会成功。字符串不能包含任何字母。因为只要字符串以数字开头,std::strtol() 就可以进行类型转换,因此示例 25.3 中使用了更自由的转换器 string_to_int_translator。

示例 25.4。 boost::property_tree::ptree 的各种成员函数

如果要读取键的值,可以调用成员函数 get_optional(),但不确定该键是否存在。 get_optional() 返回 boost::optional 类型对象中的值。如果未找到密钥,则该对象为空。否则,get_optional() 的工作方式与 get() 相同。

看起来 put_child() 和 add_child() 与 put() 相同。不同之处在于 put() 只创建一个键/值对,而 put_child() 和 add_child() 插入整个子树。请注意,类型为 boost::property_tree::ptree 的对象作为第二个参数传递给 put_child() 和 add_child()。

put_child() 和 add_child() 之间的区别在于 put_child() 会在该键已经存在时访问该键,而 add_child() 总是将一个新键插入到树中。这就是示例 25.4 中的树有两个名为“D:.Program Files”的键的原因。根据用例,这可能会令人困惑。如果一棵树代表一个文件系统,则不应有两条相同的路径。如果您不想在树中重复,则必须避免插入相同的键。

示例 25.4 显示了 for 循环中“D:”下方键的值。该示例将 50 个文件和 60 个文件写入标准输出,这证明有两个相同的键,称为“D:.Program Files”。

示例 25.4 中引入的最后一个成员函数是 get_child_optional()。此函数的使用方式与 get_child() 类似。 get_child_optional() 返回 boost::optional 类型的对象。如果您不确定密钥是否存在,则调用 boost::optional。

示例 25.5。以 JSON 格式序列化 boost::property_tree::ptree

#include 
#include 
#include 
using namespace boost::property_tree;
int main()
{
  ptree pt;
  pt.put("C:.Windows.System", "20 files");
  pt.put("C:.Windows.Cursors", "50 files");
  json_parser::write_json("file.json", pt);
  ptree pt2;
  json_parser::read_json("file.json", pt2);
  std::cout << std::boolalpha << (pt == pt2) << '\n';
}

Boost.PropertyTree 不仅仅提供结构来管理内存中的数据。从示例 25.5 中可以看出,该库还提供了将 boost::property_tree::ptree 保存在文件中并从文件中加载的函数。

头文件 boost/property_tree/json_parser.hpp 提供对函数 boost::property_tree::json_parser::write_json() 和 boost::property_tree::json_parser::read_json() 的访问。这些函数可以保存和加载以 JSON 格式序列化的 boost::property_tree::ptree。这样您就可以支持 JSON 格式的配置文件。

如果要调用将 boost::property_tree::ptree 存储在文件中或从文件中加载的函数,则必须包含头文件,例如 boost/property_tree/json_parser.hpp。仅包含 boost/property_tree/ptree.hpp 是不够的。

除了函数 boost::property_tree::json_parser::write_json() 和 boost::property_tree::json_parser::read_json() 之外,Boost.PropertyTree 还提供了其他数据格式的函数。您使用来自 boost/property_tree/ini_parser.hpp 的 boost::property_tree::ini_parser::write_ini() 和 boost::property_tree::ini_parser::read_ini() 来支持 INI 文件。使用来自 boost/property_tree/xml_parser.hpp 的 boost::property_tree::xml_parser::write_xml() 和 boost::property_tree::xml_parser::read_xml(),可以以 XML 格式加载和存储数据。使用来自 boost/property_tree/info_parser.hpp 的 boost::property_tree::info_parser::write_info() 和 boost::property_tree::info_parser::read_info(),您可以访问另一种为序列化 Boost 中的树而开发和优化的格式.PropertyTree。

任何受支持的格式都不能保证 boost::property_tree::ptree 在保存和重新加载后看起来是一样的。例如,JSON 格式可能会丢失类型信息,因为 boost::property_tree::ptree 无法区分 true 和“true”。类型始终相同。即使各种函数可以轻松保存和加载 boost::property_tree::ptree,但不要忘记 Boost.PropertyTree 并不完全支持这些格式。该库的主要重点是结构 boost::property_tree::ptree,而不是支持各种数据格式。

练习

创建一个加载此 JSON 文件并将所有动物的名称写入标准输出的程序。如果“all”设置为 true,则程序不仅应将所有动物的名称,而且应将所有属性写入标准输出:

{
  "animals": [
    {
      "name": "cat",
      "legs": 4,
      "has_tail": true
    },
    {
      "name": "spider",
      "legs": 8,
      "has_tail": false
    }
  ],
  "log": {
    "all": true
  }
}

到此这篇关于C++ Boost PropertyTree示例超详细讲解的文章就介绍到这了,更多相关C++ Boost PropertyTree内容请搜索码农之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持码农之家!


参考资料

相关文章

  • C++ IO设备读写功能实现详解

    发布:2023-03-10

    C++的文件IO(Input,Output)操作就是指对文件进行读写(输入与输出)的操作。输入就是从磁盘上的文件中读取内容到内存中。输出就是将内存中的数据内容输出或者说写入到磁盘的文件中,这篇文章主要介绍了C++ IO设备读写功能实现


  • C C++ 题解LeetCode2360图中的最长环示例

    发布:2023-03-04

    这篇文章主要为大家介绍了C C++ 题解LeetCode2360图中的最长环示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪


  • 超详细解析C++实现归并排序算法

    发布:2023-03-02

    归并排序是比较稳定的排序方法。它的基本思想是把待排序的元素分解成两个规模大致相等的子序列。本文将用C++实现这一排序算法,需要的可以参考一下


  • C++树之遍历二叉树实例详解

    发布:2022-04-11

    这篇文章主要给大家介绍了关于C++树之遍历二叉树的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧


  • C++中高性能内存池的实现详解

    发布:2023-03-05

    在 C/C++ 中,内存管理是一个非常棘手的问题,我们在编写一个程序的时候几乎不可避免的要遇到内存的分配逻辑。本文将通过C++实现高性能内存池,感兴趣的可以了解一下


  • C++时间函数整理详解

    发布:2023-03-07

    C++中并没有针对时间特意提供特定的时间类型,而是直接继承了C语言的结构以及函数,因此在C++中使用时间函数需要引用<ctime>头文件,这篇文章主要介绍了C++时间函数


  • C++提取文件名与提取XML文件的方法详解

    发布:2022-10-10

    给网友们整理关于C++的教程,这篇文章主要为大家详细介绍了C++提取文件名与提取XML文件的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助


  • C++资源管理操作方法详解

    发布:2023-03-02

    系统中的资源,诸如动态申请的内存,文件描述符,数据库连接,网络socket等,在不用的时候,应该及时归还给系统,否则就会造成内存泄露


网友讨论