读写YAML文件

最近想着实现一个能够运动的障碍物,结果搞出一大堆的概念需要整理!

1. 依赖库

在网上找到一个用于解析和构造YAML文件的工具库yaml-cpp。关于这个库,有几点需要提示的:

  • 实践平台:Ubuntu 16.04

  • 目前该库已经更新到0.6版本,其中0.5.x以上的版本都使用新的API接口,之前的版本使用的是旧的API接口,本文使用yaml-cpp.0.6版本。同时0.6版本的需要C++11支持

  • 安装流程

$ git clone https://github.com/jbeder/yaml-cpp.git
# 也可以采用从Releases下载稳定版的方式下载源码
$ mkdir build
$ cd build
# 默认生成静态链接库,配置生成动态链接库
$ cmake -DYAML_BUILD_SHARED_LIBS=ON ..
$ make
$ sudo make install

2. 读取YAML文件

  • 文件结构:典型的cmake项目
├── build
    ├── game.yaml
    └── config.yaml
├── CMakeLists.txt
└── main.cpp
  • config.yaml
    yaml-cpp解析文件后,node的数据类型如下:
1: none
2: Scalar
3: Sequence
4: Map

game.yaml文件内容如下:

trajectory:
  - name: Tim
    age: 18
    numbers: [1, 2, 1, 4]
  - name: John
    age: 18
    numbers: [1, 3, 1, 4]

config.yaml文件内容如下:

containers:
  - name: Tim
    age: 18
    numbers: [1, 2, 1, 4]
  - name: John
    age: 18
    numbers: [1, 3, 1, 4]
  • CMakeLists.txt
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(yaml_demo)

SET( CMAKE_CXX_FLAGS "-std=c++11")
find_package(yaml-cpp REQUIRED)

if (yaml-cpp_FOUND)
    message(STATUS "找到yaml-cpp:\"${YAML_CPP_INCLUDE_DIR}\"")
    message(STATUS "找到yaml-cpp Libraries:\"${YAML_CPP_LIBRARIES}\"")
endif (yaml-cpp_FOUND)

add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} yaml-cpp) 
  • main.cpp
// https://github.com/jbeder/yaml-cpp/wiki/Tutorial
#include 
#include 
#include 
#include 
#include 

struct Container
{
    std::string name;
    int age;
    std::vector numbers;
};

namespace YAML
{
    template <>
    struct convert
    {
        static Node encode(const Container &player)
        {
            Node node;
            node.push_back(player.name);
            node.push_back(player.age);
            node.push_back(player.numbers);
            return node;
        }

        static bool decode(const Node &node, Container &player)
        {
            player.name = node["name"].as();
            player.age = node["age"].as();
            player.numbers = node["numbers"].as>();
            return true;
        }
    };
} // namespace YAML

int main(int argc, char **argv)
{
    // 读取文件
    // ============================================================================
    std::string config_path = "./config.yaml";
    std::cout << config_path << std::endl;
    YAML::Node config = YAML::LoadFile(config_path);

    // node类型也可以直接文件保存
    // ofstream fout("testconfig.yaml");
    // fout << config;
    // fout.close();

    // trajectory:
    //   - name: 222
    //     age: 18
    //     numbers: [1, 2, 1, 4]
    //   - name: 222
    //     age: 18
    //     numbers: [1, 2, 1, 4]

    // 该文件的整体类型为Map格式,Size为1,包含trajectory节点
    // trajectory节点类型为Sequences格式,Size为2,包含Map类型的数据
    // 

    // 获取containers中的数据内容
    std::vector vi = config["containers"].as>();


    std::vector numberVec;

    for (std::vector::iterator it = vi.begin(); it != vi.end(); ++it)
    {
        // 其中it为相关container的指针,而container为结构体,故it无法直接输出
        std::cout << it->name << std::endl;
        std::cout << it->age << std::endl;

        // 无法直接输出numbers,因为numbers为一个vector
        numberVec = it->numbers;
        for (int n = 0; n < numberVec.size(); n++)
        {
            std::cout << numberVec[n] << " ";
        }
        std::cout << " " << std::endl;
    }

    // 保存文件:需要输出的文件名
    // ============================================================================
    std::ofstream fout("game.yaml");

    YAML::Emitter emitter;
    emitter << YAML::BeginMap;
    emitter << YAML::Key << "trajectory";

    emitter << YAML::BeginSeq;
    for (int i = 0; i < vi.size(); i++)
    {
        emitter << YAML::BeginMap;
        emitter << YAML::Key << "name" << YAML::Value << vi[i].name;
        emitter << YAML::Key << "age" << YAML::Value << vi[i].age;;
        emitter << YAML::Key << "numbers" << YAML::Flow << vi[i].numbers;
        emitter << YAML::EndMap;
        
    }
    emitter << YAML::EndSeq;
    emitter << YAML::EndMap;
    std::cout << "Here's the output YAML:\n" << emitter.c_str() << std::endl;
    fout << emitter.c_str();
    fout.close();

    return 0;
}

3. Errors

  • 无法解析或打开软件包的列表或是状态文件
E: Encountered a section with no Package: header
E: Problem with MergeList /var/lib/apt/lists/ppa.launchpad.
net_maarten-baert_simplescreenrecorder_ubuntu_dists_xenial_main_binary-amd64_Packages

解决方案:

$ sudo rm /var/lib/apt/lists/* -vf
$ sudo apt-get update
  • 软件卸载指令记录
# 只卸载软件包
$ sudo apt-get remove package_name
# 卸载软件包及其依赖
$ sudo apt-get remove --auto-remove package_name
# 清除软件包和软件的配置文件
$ sudo apt-get purge package_name
# 清除软件包及其依赖,以及对应的配置文件
$ sudo apt-get purge --auto-remove package_name
  • 查看库位置
ldconfig -p | grep lib_name
  • CMakeLists.txt语法糖
# 在CMakeLists.txt文件中打印出里面定义的变量的值
MESSAGE("include folder: "${include_dir})

# 实例:可以查看/usr/local/lib文件下的动态链接库的名字
find_package(yaml-cpp REQUIRED)

if (yaml-cpp_FOUND)
    message(STATUS "找到yaml-cpp:\"${YAML_CPP_INCLUDE_DIR}\"")
    message(STATUS "找到yaml-cpp Libraries:\"${YAML_CPP_LIBRARIES}\"")
endif (yaml-cpp_FOUND)

# 上述实例的yaml-cpp在两个地方均存在大小写的区别
# 常见的名字有:首字母大写,全部小写或大写
# name_INCLUDE_DIRS
# name_INCLUDE_DIR
# NAME_INCLUDE_DIRS
# NAME_INCLUDE_DIR
# name_LIBS
# NAME_LIBS
# name_LIBRARIES
# NAME_LIBRARIES

4. 参考链接

1. 项目地址

你可能感兴趣的:(读写YAML文件)