YAML-CPP
yaml作为一种便捷的文件格式,通过c++进行操作时,可以利用yaml-cpp进行。
一,yaml-cpp的安装
下载源码
git clone https://github.com/jbeder/yaml-cpp.git
编译安装
mkdir build
cd build
cmake -DBUILD_SHARED_LIBS=ON .. # ON 设置生成共享库
sudo make install
验证
pkg-config --modversion yaml-cpp
使用
YAML::Node node1 = YAML::LoadFile("config.yaml"); // 加载文件
YAML::Node node2 = YAML::Load("[1,2,3]"); // 加载数组
cout << node1[0].as<string>() << endl;
cout << node2[0].as<int>() << endl; // 输出元素
更多API参考yaml-cpp docs。
示例:
a、CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(yaml_test)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
link_directories(/home/jonty/Softwares/yaml-cpp/build)
include_directories(/home/jonty/Softwares/yaml-cpp/include/yaml-cpp)
add_executable(test main.cpp)
target_link_libraries(test yaml-cpp)
b、main.cpp
#include <iostream>
#include "yaml.h"
using namespace std;
int main()
{
YAML::Node node = YAML::Load("[22,3,4,4]");
cout << node[0] << endl;
YAML::Node node2 = YAML::LoadFile("../config.yaml");
cout << node2["ttt"] << endl;
return 0;
}
编译运行
mkdir build
cd build
cmake ..
make
./test
参考教程https://github.com/jbeder/yaml-cpp/wiki/Tutorial
编译也可以采用g++ test.cpp /usr/local/lib/libyaml-cpp.a -std=c++11
源码编译yaml-cpp
git clone https://github.com/jbeder/yaml-cpp.git
cd yaml-cpp # 进入克隆的文件夹
mkdir build
cd build
cmake ..
make
make install
可参考https://blog.csdn.net/Fourier_Legend/article/details/82798297
记得在CMakeLists.txt中加入
link_directories(/usr/local/lib)
include_directories(/usr/local/include/yaml-cpp)
以及在链接库target_link_libraries时,加上yaml-cpp。
void write_robot_status_to_yaml(string path, const string &filename, double x, double y, double th) { //dir_file_exists(path, true); dir_file_exists(path, false, true, filename.c_str()); std::ofstream yaml_file(path + filename, std::ios::out | std::ios::binary); { YAML::Emitter out(yaml_file); out << YAML::BeginMap; // TODO(whess): Use basename only? out << YAML::Key << "x"; out << YAML::Value << x; out << YAML::Key << "y"; out << YAML::Value << y; out << YAML::Key << "th"; out << YAML::Value << th; out << YAML::EndMap; } yaml_file.close(); }
bool read_robot_status_from_yaml(string file_path, const string &file_name, double &x, double &y, double &th) { if (!dir_file_exists(file_path, false, true, file_name.c_str())) return false; std::ifstream yaml_file(file_path + file_name, std::ios::out | std::ios::binary); { YAML::Node doc = YAML::Load(yaml_file); doc["x"] >> x; doc["y"] >> y; doc["th"] >> th; } yaml_file.close(); return true; }
/* * @brief 创建文件夹 */ bool dir_file_exists(string dir, bool mkdir_flag, bool touchfile_flag, string filename) { char des_dir[255]; str_2_char(dir, des_dir); int state = access(des_dir, R_OK | W_OK);//#include<unistd.h> if(state == 0) { ROS_INFO("state == 0"); return true; } else if(mkdir_flag) { dir = "mkdir " + dir; str_2_char(dir, des_dir); if(system(des_dir)) { printf("generate dir %s successfully.",dir.c_str()); ROS_INFO("generate dir %s successfully.",dir.c_str()); //Basic_Info("generate dir {} successfully.",dir.c_str()); } else { printf("generate dir %s fail.",dir.c_str()); ROS_INFO("generate dir %s fail.",dir.c_str()); //Basic_Info("generate dir {} fail.",dir.c_str()); } return true; } else if(touchfile_flag) { dir = "touch " + dir + "/" + filename; ROS_INFO("dir is %s", dir.c_str()); str_2_char(dir, des_dir); if(system(des_dir)) { printf("generate filename %s successfully.",dir.c_str()); ROS_INFO("generate filename %s successfully.",dir.c_str()); //Basic_Info("generate filename {} successfully.",dir.c_str()); } else { printf("generate filename %s fail.",dir.c_str()); ROS_INFO("generate filename %s fail.",dir.c_str()); //Basic_Info("generate filename {} fail.",dir.c_str()); } return true; } return false; }
template <typename T> void operator>>(const YAML::Node& node, T& i); template <typename T> void operator>>(const YAML::Node& node, T& i) { i = node.as<T>(); };
写个模板类加载参数
template<typename T> T getParam(const string& name,const T& defaultValue) //This name must be namespace+parameter_name { T v; if(ros::param::get(name,v)) //get parameter by name depend on ROS. { ROS_INFO_STREAM("Found parameter: "<<name<<",\tvalue: "<<v); return v; } else ROS_WARN_STREAM("Cannot find value for parameter: "<<name<<",\tassigning default: "<<defaultValue); return defaultValue; //if the parameter haven't been set,it's value will return defaultValue. }
在ROS系统中,参数读写一般通过xml或者yaml格式的文件,其中yaml用得比较多。这是一种可读性高,轻量级的标记语言,简单好用。
对于yaml文件,ros中用的较早版本的yaml-cpp库,最新的可在github上下载,并按照readme中所述的方法编译安装。
特别留意的是,如果需要生成共享库,cmake的时候后面一定要加上 -DBUILD_SHARED_LIBS=ON 这句话。
有了yaml库,在CMakeLists.txt中加入,
link_directories(/usr/local/lib)
include_directories(/usr/local/include/yaml-cpp)
最后别忘了在链接库target_link_libraries时,加上yaml-cpp。
关于库的使用,github上有一些简单的tutorial教程。
以下是简单的yaml文件读写操作示例。
#include <ros/ros.h> #include <yaml-cpp/yaml.h> #include <iostream> #include <fstream> int main(int argc, char **argv) { std::string fin = "/home/user/param/param.yaml"; //yaml文件所在的路径 YAML::Node yamlConfig = YAML::LoadFile(fin); int int_param = yamlConfig["int_param"].as<int>(); std::cout << " node size: " << yamlConfig.size() << std::endl; std::cout << yamlConfig["bool_param"].as<bool>() << "\n"; yamlConfig["bool_param"] = !yamlConfig["bool_param"].as<bool>(); yamlConfig["str_param"] = "test"; std::ofstream file; file.open(fin); file.flush(); file << yamlConfig; file.close(); return 0; }
其中,yaml文件里的内容为:
bool_param: true
int_param: 2
double_param: 0.5
str_param: "123"
也可采用Emit来生成yaml文件,代码如下:
#include <ros/ros.h> #include <yaml-cpp/yaml.h> #include <iostream> #include <fstream> int main(int argc, char **argv) { std::ofstream fout("/home/user/param/param.yaml"); YAML::Emitter out(fout); out << YAML::BeginMap; out << YAML::Key << "int_param"; out << YAML::Value << 1; out << YAML::Key << "double_param"; out << YAML::Value << 0.5; out << YAML::Key << "bool_param"; out << YAML::Value << false; out << YAML::Comment("bool parameter"); out << YAML::Key << "str_param"; out << YAML::Value << "test"; out << YAML::EndMap; return 0; }
yml文件的其他操作可参见博文《.yaml参数文件的编写和使用》,
其综合运用的案例可参见博文:ros-opencv-qt-yaml综合运用之滤波。