C++中使用YAML语言


这篇文章是有关C++中使用YAML语言的基础,以及在结合ROS和OpenCV使用的学习内容。

YAML语言使用基础

YAML语言在C++中,可以用于应用程序相关配置文件的保存,可读性、可修改性比较好。直接贴代码。

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
#include <fstream>
#include <iostream>
#include <string>
#include <assert.h>
#include "yaml-cpp/yaml.h"

using namespace std;

//=============================================================================
void test1()
{
YAML::Node config = YAML::LoadFile("site.yaml");

std::cout<<"here test1!!"<<endl;
YAML::Node config_systemLog = config["systemLog"];

if ( config_systemLog["path"] )
std::cout << config_systemLog["path"] << std::endl;//输出c:\data\log\mongod.log

std::ofstream fout( "test1.yaml" );
fout << config;
}

//=============================================================================
void test2()
{
YAML::Node node;
node["username"] = "glimix";
node["password"] = "111222";

std::ofstream fout( "test2.yaml" );
fout << node;
}

//=============================================================================
void test3()
{
try
{
YAML::Node doc = YAML::LoadFile( "Night.jpg.meta" );
std::cout << doc << "\n";
}
catch( const YAML::Exception &e )
{
std::cerr << e.what() << "\n";//读取文件异常
}
}

//=============================================================================
void test4()
{
YAML::Node node;
node.push_back( "glimix" );
node.push_back( 123 );
node.push_back( 3.1415926 );
node["char"].push_back( 'a' );
node["bool"].push_back( true );

std::ofstream fout( "test4.yaml" );
fout << node;
}

//=============================================================================
void test5()
{
class Vector3
{
public:
float x, y, z;

void encode( YAML::Node &node )
{
node.push_back( x );
node.push_back( y );
node.push_back( z );
}

bool decode( YAML::Node &node )
{
if ( !node.IsSequence() || node.size() != 3 )
return false;

x = node[0].as<float>();
y = node[1].as<float>();
z = node[2].as<float>();

return true;
}
};

Vector3 pos;
pos.x = 100.0f; pos.y = -45.0f; pos.z = 50.0f;

YAML::Node node;
pos.encode( node );

std::ofstream fout( "test5.yaml" );
fout << node;

Vector3 pos2;
pos2.decode( node );
}

//=============================================================================
void test6()
{
YAML::Node node;
node["name"] = "John Smith";
node["age"] = 37;

YAML::Node node2;
node2["name"] = "Jane Smith";
node2["age"] = 25;

YAML::Node node3;
node3["name"] = "Jimmy Smith";
node3["age"] = 15;

YAML::Node node4;
node4["name"] = "Jenny Smith";
node4["age"] = 12;

node["spouse"] = node2;
node["children"].push_back( node3 );
node["children"].push_back( node4 );

node["children"].push_back( "{name: Alex Smith, age: 14}" );
node["children"].push_back( "name: Alex Smith, age: 14" );
node["children"].push_back( YAML::Load( "{name: Alex Smith, age: 14}" ) );
YAML::Node node5 = YAML::Load( "{name: Alex Smith, age: 14}" );
node["children"].push_back( node5 );

std::ofstream fout( "test6.yaml" );
fout << node;
}

//=============================================================================
void test7()
{
YAML::Node node; // starts out as null
node["key"] = "value"; // it now is a map node
node["seq"].push_back("first element"); // node["seq"] automatically becomes a sequence
node["seq"].push_back("second element");

node["mirror"] = node["seq"][0]; // this creates an alias
node["seq"][0] = "1st element"; // this also changes node["mirror"]
node["mirror"] = "element #1"; // and this changes node["seq"][0] - they're really the "same" node

node["self"] = node; // you can even create self-aliases
node[node["mirror"]] = node["seq"]; // and strange loops 🙂


std::ofstream fout( "test7.yaml" );
fout << node;
}

//=============================================================================
void test8()
{
YAML::Node primes = YAML::Load("[2, 3, 5, 7, 11]");
for (std::size_t i=0;i<primes.size();i++)
{
std::cout << primes[i].as<int>() << "\n";
}
// or:
// for (YAML::const_iterator it=primes.begin();it!=primes.end();++it)
// {
// std::cout << it->as<int>() << "\n";
// }

primes.push_back(13);
assert(primes.size() == 6);
std::ofstream fout("test8.yaml");
fout << primes;
}

//=============================================================================
void test9()
{
YAML::Node lineup = YAML::Load("{1B: Prince Fielder, 2B: Rickie Weeks, LF: Ryan Braun}");
for(YAML::const_iterator it = lineup.begin(); it != lineup.end(); ++it)
{
std::cout << "Playing at " << it->first.as<std::string>() << " is " << it->second.as<std::string>() << "\n";
}

lineup["RF"] = "Corey Hart";
lineup["C"] = "Jonathan Lucroy";
assert(lineup.size() == 2);//assert(表达式)保证满足特定条件,即表达式为真,否则整个程序退出并输出一条错误信息。

std::ofstream fout("test9.yaml");
fout << lineup;
}

//=============================================================================
void test10()
{
YAML::Node node = YAML::Load("{name: Brewers, city: Milwaukee}");

if (node["name"]) {
std::cout << node["name"].as<std::string>() << "\n";
}
if (node["mascot"]) {//无输出
std::cout << node["mascot"].as<std::string>() << "\n";
}
assert(node.size() == 2); // the previous call didn't create a node
}

//=============================================================================
void test11()
{
YAML::Node node1 = YAML::Load("[1, 2, 3]");//序列结构
assert(node1.Type() == YAML::NodeType::Sequence);
assert(node1.IsSequence()); // a shortcut!

YAML::Node node2 = YAML::Load("{name: Brewers, city: Milwaukee}");//散列/map结构
switch (node2.Type())
{
case YAML::NodeType::Null: cout<<"NodeType:NULL"<<endl; break;
case YAML::NodeType::Scalar: cout<<"NodeType:Scalar"<<endl; break;
case YAML::NodeType::Sequence: cout<<"NodeType:Sequence"<<endl; break;
case YAML::NodeType::Map: cout<<"NodeType:Map"<<endl; break;//输出为Map
case YAML::NodeType::Undefined: cout<<"NodeType:Undefined"<<endl; break;
}
}

//=============================================================================
int main(int argc ,char **argv)
{
test11();
return 0;
}

测试输出文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#test1
systemLog:
destination: file
path: c:\data\log\mongod.log
storage:
dbPath: c:\data\db
security:
authorization: enabled
net:
bindIp: 127.0.0.1
port: 27017

#test2
username: glimix
password: 111222

#test4
0: glimix
1: 123
2: 3.1415926
char:
- a
bool:
- true

#test5
- 100
- -45
- 50

#test6
name: John Smith
age: 37
spouse:
name: Jane Smith
age: 25
children:
- name: Jimmy Smith
age: 15
- name: Jenny Smith
age: 12
- "{name: Alex Smith, age: 14}"
- "name: Alex Smith, age: 14"
- {name: Alex Smith, age: 14}
- {name: Alex Smith, age: 14}

#test7
&1
key: value
seq: &2
- &3 "element #1"
- second element
mirror: *3
self: *1
*3: *2

#test8
[2, 3, 5, 7, 11, 13]

#test9
{1B: Prince Fielder, 2B: Rickie Weeks, LF: Ryan Braun, RF: Corey Hart, C: Jonathan Lucroy}

site.yaml文件(注意:冒号和其后内容之间有一空格):

1
2
3
4
5
6
7
8
9
10
systemLog:
destination: file
path: c:\data\log\mongod.log
storage:
dbPath: c:\data\db
security:
authorization: enabled
net:
bindIp: 127.0.0.1
port: 27017

CMakeLists.txt文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 使用c++11编译
add_compile_options(-std=c++11)
cmake_minimum_required(VERSION 2.6)
project(test)

find_package(yaml-cpp REQUIRED)

Message("YAML_INCLUDE:${YAML_CPP_INCLUDE_DIR}")

include_directories(${PROJECT_SOURCE_DIR} ${YAML_CPP_INCLUDE_DIR})
set(LIBS ${YAML_CPP_LIBRARIES})
add_executable(test main.cpp)
target_link_libraries(test ${LIBS})

结合ROS+OpenCV的使用

在许多ROS项目中使用YAML文件作为配置文件可以简化程序、提高代码的可读性和可修改性,在结合OpenCV的一些API,可以很方便地对配置信息进行修改,而不需要修改程序。下面是结合ROS+OpenCV读取YAML文件的一小段示例代码(未运行)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <ros/ros.h>
#include <ros/package.h> //ros::packgae
#include <opencv2/opencv.hpp> //cv::FileStorage

int main(int argc, char** argv)
{
ros::init(argc, argv, "node_name");
string packagePath = ros::package::getPath("package_name"); //使用ROS包名读取包的地址
string configPath = packagePath + "//config//config_name.yaml"; //YAML文件
cv::FileStorage fsSettings(configPath, cv::FileStorage::READ); //cv::FileStorage适用于XML/YAML/JSON文件
if(!fsSettings.isOpened())
{
cerr << "ERROR: Wrong path to settings" << endl;
return -1;
}
string config_variable_name = fsSettings["config_variable_name"];
//...
return 0;
}

YAML文件:

1
2
3
config_variable_name: value
str_name: "value"
...

参考资料

https://github.com/jbeder/yaml-cpp/wiki/Tutorial

http://www.glimix.com/archives/1570

http://yaml.org/

本文标题:C++中使用YAML语言

文章作者:阿翔

发布时间:2018年05月23日 - 09:05

最后更新:2019年05月28日 - 21:05

原始链接:http://ttshun.com/2018/05/23/C++中使用YAML语言/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

点击给我一些鼓励叭!
-------------本文结束感谢您的阅读-------------
0%