赞
踩
YAML是一个开源库,源代码可以在GitHub下载到,链接:
https://github.com/jbeder/yaml-cpp
yaml-cpp 是通过 CMake 来进行构建和编译的。使用CMake的方法可以自行百度,网上
一大堆。
直接百度网盘下载我这里构建好的,包含64位和32位两个版本。
附上链接:
链接:https://pan.baidu.com/s/1_QYPX2IpP7UWlEteRJCeqw
提取码:ehmp
嫌麻烦的或者没有CMake操作经验的,可以直接百度网盘下载对应文件。
首先根据自己需要下载一个32位或者64位的控制台程序。将下载好或者自行编译好的文件夹放到自己的工程目录下面。为了操作方便,我这里直接放到了了和 .sln 同一级的目录下。
用vs打开工程之后,点击上方工具栏中的项目,找到最下方的项目属性。分别在属性页中的C/C++:常规。链接器:常规和输入完成相关配置。配置结果如下。
使用过C/C++编程的人都知道,在使用某个库之前,我们需要包含它的头文件,然后才能使用里面的函数。在上面链接好工程之后,在main.cpp里面包含YAML库的头文件,如果能包含成功,则说明配置无误,若包含失败,请检查上面操作步骤。
完成操作之后,我们开始文件的基本操作 “增删改查”。
一般来说,我们用C/C++进行文件操作时,需要不断偏移文件的指针去解析自己想要的内容。在YAML操作这里,首先让我们先忘掉指针操作。
name: dong
number: 1
age:
skills:
eat: 2
drink: 3
play: 4
study: 5
self: 99
这里有一点需要注意,YAML是一个严格按照空格进行区分节和子节的一种格式语言。若不在同一缩进的格式下,计时在同一个节下面,也会将其分为不同子节。下面验证一下。
YAML文件的增加操作,目前我喜欢用两种方法,分别为 push_back方法和数组操作方法,下面用一段代码分别介绍。
YAML::Node config; //< 创建节点
config.IsNull(); //< 初始化节点
ofstream fout("../dong1.yaml"); //< C++ stream 读取文件
config["123"] = 456; //< 插入格式 1 直接插入第一节
config["456"].push_back(789); //< 插入格式2 插入第一节
fout << config;
fout.close();
这里可以看一下两者放入方法的不同区别:贴图如下:
可以看到,用第一种方法插入的直接对键进行了赋值,第二种方法,则是在键下面新建了一个 “标量”。可以根据需要来决定采取何种插入方法。这里可能会有人有疑问:如果我想要在某一个子节下面增加数据,该如何操作。下面贴上代码:
YAML::Node config; //< 创建节点
config.IsNull(); //< 初始化节点
ofstream fout("../dong1.yaml"); //< C++ stream 读取文件
config["123"]["456"] = 456; //< 插入格式 1 直接插入第一节
config["456"].push_back(789); //< 插入格式2 插入第一节
fout << config;
fout.close();
只需要在后面新加一个中括号即可解决问题。
YAML文件的删除需要用到 remove函数。该函数有两种用法,下面用一个例子来分别介绍。
源数据:
name: dong
number: 1
skills:
eat: 2
drink: 3
play: 4
study: 5
self: 99
remove的用法:
//< 删
YAML::Node config = YAML::LoadFile("../dong.yaml");
config["skills"].remove("eat");//< 1、删除skills下面的eat元素
config.remove("number");//< 2、通过指定key来删除
ofstream fout("../dong2.yaml"); //< C++ stream 读写文件
fout << config;
fout.close();
运行完之后的结果如下图:
可以看到已经将所指出的饿两个文件删除掉了
改操作和上面的增操作类似,增操作是新增一个不存在的键或者节。改的操作只需要将其修改为已经存在的值,具体实现如下:
//< 改
YAML::Node config = YAML::LoadFile("../dong.yaml");
ofstream fout("../dong1.yaml"); //< C++ stream 读取文件
config["skills"]["eat"] = 10; //< 修改格式 1
config["name"] = "hening"; //< 修改格式2
fout << config;
fout.close();
可以看到,上面分别修改了两个点的内容,修改结果如下所示:
可以看到,修改操作和插入操作基本相同。
查询操作基本上是我们用到的最多的操作了,了解到了以上三种 增、删、改的操作,下面的查询操作基本上就是小菜一碟了,下面首先介绍一下yaml的几种数据类型。
//分别为:未定义、空、标量、序列、字典。
enum value { Undefined, Null, Scalar, Sequence, Map };
用代码验证一下上面:
YAML::Node test1 = YAML::Load("[1,2,3,4]");
cout << " Type: " << test1.Type() << endl; //< 3
YAML::Node test2 = YAML::Load("1");
cout << " Type: " << test2.Type() << endl; //< 2
YAML::Node test3 = YAML::Load("{'first':'dong' 'last':'hening'}");
cout << " Type: " << test3.Type() << endl; //< 4
分别对应位 序列、标量以及字典:
依旧是读取dong.yaml文件的内容。
基本查询,首先查询节的内容,不包括子节。
在这里插入代码片 YAML::Node config = YAML::LoadFile("../dong.yaml");
for (auto it : config) {
cout << it.first.as<string>() << endl; //< 指定数据类型
}
//< 这里使用 auto 可能不好理解,下面给出基本迭代器的使用
for (YAML::const_iterator it = config.begin(); it != config.end(); it++){
cout << it->first.as<string>() << endl;
}
这里使用迭代器的方法进行查询,查询到的结果需要为其指定数据类型后输出。
运行结果如下:
如果我们想要查询子键的内容该如何去操作,基本上和上面的操作相同,只需要在中括号内为其指定即可:
YAML::Node config = YAML::LoadFile("../dong.yaml");
for (auto it : config["skills"]) {
cout << it.first.as<string>() << ":" << it.second.as<string>() << endl;
}
运行结果:
这里有一点需要注意,我这里采用了second来读取了该键所对应的值,若此键没有设置值该怎么办?
下面我把eat所对应的2删除掉,运行一遍,给出结果:
他为我们自动填充了null类型,此时我们若要采用此值就需要判断其数据类型。
YAML::Node config = YAML::LoadFile("../dong.yaml");
for (auto it : config["skills"]) {
YAML::Node test2 = YAML::Load(it.second.as<string>());
cout << " Type: " << test2.Type() << endl; //< 2
cout << it.first.as<string>() << ":" << it.second.as<string>() << endl;
}
可以看到运行结果,判断类型为空。可以根据判断的类型做特殊处理。
这里我们修改文件如下:
可以看到,我们给skills设置了值,这里看一下运行结果:
直接报出异常!结论显而易见。不能再一个键值对下面设置子键。对于节和键要区分开来。
贴上完整代码:
#include <iostream> #include "yaml-cpp/yaml.h" #include <string> #include <fstream> using namespace std; //分别为:未定义、空、标量、序列、字典。 //enum value { Undefined, Null, Scalar, Sequence, Map }; int main(){ //< 增 //YAML::Node config; //< 创建节点 //config.IsNull(); //< 初始化节点 //ofstream fout("../dong1.yaml"); //< C++ stream 读取文件 //config["123"]["456"] = 456; //< 插入格式 1 直接插入第一节 //config["456"].push_back(789); //< 插入格式2 插入第一节 //fout << config; //fout.close(); //< 删 //YAML::Node config = YAML::LoadFile("../dong.yaml"); //config["skills"].remove("eat");//你可以通过指定一个node来删除它 //config.remove("number");//你也可以通过指定key来删除它 //ofstream fout("../dong2.yaml"); //< C++ stream 读取文件 //fout << config; //fout.close(); < 改 //YAML::Node config = YAML::LoadFile("../dong.yaml"); //ofstream fout("../dong1.yaml"); //< C++ stream 读取文件 //config["skills"]["eat"] = 10; //< 修改格式1 //config["name"] = "hening"; //< 修改格式2 //fout << config; //fout.close(); < 查 // ///< Type Judge link to row 112 to 113 //YAML::Node test1 = YAML::Load("[1,2,3,4]"); //cout << " Type: " << test1.Type() << endl; //< 3 //YAML::Node test2 = YAML::Load("1"); //cout << " Type: " << test2.Type() << endl; //< 2 //YAML::Node test3 = YAML::Load("{'id':1 'degree':'senior'}"); //cout << " Type: " << test3.Type() << endl; //< 4 YAML::Node config = YAML::LoadFile("../dong.yaml"); for (auto it : config["skills"]) { YAML::Node test2 = YAML::Load(it.second.as<string>()); cout << " Type: " << test2.Type() << endl; //< 2 cout << it.first.as<string>() << ":" << it.second.as<string>() << endl; } for (YAML::const_iterator it = config.begin(); it != config.end(); it++) { cout << it->first.as<string>() << endl; } system("pause"); return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。