美文网首页
读写YAML文件

读写YAML文件

作者: 酵母小木 | 来源:发表于2021-01-16 18:43 被阅读0次

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

    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 <string>
    #include <iostream>
    #include <fstream>
    #include <yaml-cpp/yaml.h>
    #include <yaml-cpp/node/parse.h>
    
    struct Container
    {
        std::string name;
        int age;
        std::vector<int> numbers;
    };
    
    namespace YAML
    {
        template <>
        struct convert<Container>
        {
            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<std::string>();
                player.age = node["age"].as<int>();
                player.numbers = node["numbers"].as<std::vector<int>>();
                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<Container> vi = config["containers"].as<std::vector<Container>>();
    
    
        std::vector<int> numberVec;
    
        for (std::vector<Container>::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文件

          本文链接:https://www.haomeiwen.com/subject/maeiaktx.html