主要介绍配置文件yaml如何读写解析。
在日常开发中,我们总能遇到一些可能需要变化的场景,这个时候就需要配置文件来实现不更换程序的情况下能够改变程序的运行参数。
常见的配置文件格式有很多种,一般包括json、protobuf、xml,还有本文的主角yaml格式。当然选择yaml的理由是因为其相比xml、json等语言简洁强大。
YAML是"YAML Ain't a Markup Language"(YAML不是一种标记语言)的递归缩写。实际上YAML 的意思其实是:"Yet Another Markup Language"(仍是一种标记语言),但为了强调这种语言以数据做为中心,而不是以标记语言为重点,而用反向缩略语重命名。
1.大小写敏感;
2.使用缩进表示层级关系;
3.只允許使用空格,不能使用tab;
4.同一层级只需要缩进相同空格即可;
5.使用#注释
首先简单写一个用于测试的相机类的配置文件,内容如下:
#全局配置参数 GlobalConfig: DeviceNum: 3 #设备配置参数 # ‘-’为数组中不同项 DeviceParam: - ID: 1 DeviceName: Dev_1 DeviceIp: 192.168.2.111 FrameRate: 24 DepthType: 3 FrameWidth: 1200 FrameHeight: 1024 TriggerInterval: 300 - ID: 2 DeviceName: Dev_2 DeviceIp: 192.168.2.112 FrameRate: 24 DepthType: 3 FrameWidth: 1200 FrameHeight: 1024 TriggerInterval: 300 - ID: 3 DeviceName: Dev_3 DeviceIp: 192.168.2.113 FrameRate: 24 DepthType: 3 FrameWidth: 1200 FrameHeight: 1024 TriggerInterval: 300
解析方如下:
注:需加上Loader = yaml.FullLoader,否则会报警告。
# coding=utf-8 import yaml with open("./config.yaml") as f: x = yaml.load(f,Loader= yaml.FullLoader) # print(x) #打印出全局配置参数中的所有设备数量 print("parse device count is ",x["GlobalConfig"]['DeviceNum']) #打印出设备配置参数中的设备1的内容 print("parse device1 param is ",x["DeviceParam"]["Device1"])
输出结果如下
parse device count is 3 parse device1 param is {'TriggerInterval': 300, 'DepthType': 3, 'ID': 1, 'DeviceName': 'Dev_1', 'DeviceFrameRate': 24, 'SourceHeight': 1024, 'DeviceIp': '192.168.2.111', 'SourceWidth': 1200}
格式化写入yaml文件:
#将固定格式的字符串组装写入wrYaml.yaml文件中 data = {"GlobalConfig":{'ConfigName':'CameraManagerConfig','DeviceNum':3},'DeviceParam':{'Device1':{'DeviceName':'Dev_1','DeviceIp':'192.168.1.100','DeviceType':3}}} with open("./wrYaml.yaml",'w') as f: yaml.dump(data,f) #读取解析wrYaml.yaml文件内容 with open("./wrYaml.yaml") as f: x = yaml.load(f,Loader= yaml.FullLoader) print(x['GlobalConfig']['DeviceNum']) print(x['DeviceParam']['Device1'])
执行后写入结果:
DeviceParam: Device1: DeviceIp: 192.168.1.100 DeviceName: Dev_1 DeviceType: 3 GlobalConfig: ConfigName: CameraManagerConfig DeviceNum: 3
C+版本的配置文件有修改,内容如下:
#全局配置参数 GlobalConfig: DeviceNum: 3 #设备配置参数 DeviceParam: - ID: 1 DeviceName: Dev_1 DeviceIp: 192.168.2.111 FrameRate: 24 DepthType: 3 FrameWidth: 1200 FrameHeight: 1024 TriggerInterval: 300 - ID: 2 DeviceName: Dev_2 DeviceIp: 192.168.2.112 FrameRate: 24 DepthType: 3 FrameWidth: 1200 FrameHeight: 1024 TriggerInterval: 300 - ID: 3 DeviceName: Dev_3 DeviceIp: 192.168.2.113 FrameRate: 24 DepthType: 3 FrameWidth: 1200 FrameHeight: 1024 TriggerInterval: 300
其中" - ID"表示三个不同数组,在python中可以直接使用config["DeviceParam"][0] 下标的方式访问。新建testYaml.cpp文件,读取解析方式如下:
#include <iostream> #include "yaml-cpp/yaml.h" #include <fstream> using namespace std; typedef struct GlobalConfig { int deviceNum; }GlbCon; typedef struct DeviceInfo { std::string DeviceName; std::string DeviceIp; int ID; int FrameRate; int DepthType; int FrameWidth; int FrameHeight; int TriggerInterval; }DevInfo; namespace YAML { template<> struct convert<GlobalConfig> { static Node encode(const GlobalConfig &globalconfig) { YAML::Node node; node.push_back(globalconfig.deviceNum); return node; } static bool decode(const Node &node, GlobalConfig &globalconfig) { globalconfig.deviceNum = node["DeviceNum"].as<int>(); return true; } }; template<> struct convert<DeviceInfo> { static Node encode(const DeviceInfo &devInfo) { YAML::Node node; node.push_back(devInfo.DeviceName); node.push_back(devInfo.DeviceIp); node.push_back(devInfo.ID); node.push_back(devInfo.FrameRate); node.push_back(devInfo.DepthType); node.push_back(devInfo.FrameWidth); node.push_back(devInfo.FrameHeight); node.push_back(devInfo.TriggerInterval); return node; } static bool decode(const Node &node, DeviceInfo &devInfo) { devInfo.DeviceName = node["DeviceName"].as<std::string>(); devInfo.DeviceIp = node["DeviceIp"].as<std::string>(); devInfo.ID = node["ID"].as<int>(); devInfo.FrameRate = node["FrameRate"].as<int>(); devInfo.DepthType = node["DepthType"].as<int>(); devInfo.FrameWidth = node["FrameWidth"].as<int>(); devInfo.FrameHeight = node["FrameHeight"].as<int>(); devInfo.TriggerInterval = node["TriggerInterval"].as<int>(); return true; } }; } int main(int argc,char** argv) { GlobalConfig globalconfig; YAML::Node config = YAML::LoadFile("./config.yaml"); std::cout << config["GlobalConfig"]["deviceNum"].as<int>() << std::endl; if(config["DeviceParam"]) { std::vector<DevInfo> vi = config["DeviceParam"].as<std::vector<DevInfo>>(); for (std::vector<DevInfo>::iterator it = vi.begin(); it != vi.end(); ++it) { std::cout << "vector: ID: " << it->ID << " name: " << it->DeviceName << std::endl; } } return 0; }
代码中encode decode部分为自定义结构体解析。
std::ofstream fout("wrYaml.yaml"); YAML::Node configWr; configWr["GlobalConfig"]["DeviceNum"] = 5; configWr["DeviceParam"]["DeviceParam"][0]["ID"] = "1"; configWr["DeviceParam"]["DeviceParam"][0]["DeviceName"] = "Dev_1"; configWr["DeviceParam"]["DeviceParam"][1]["ID"] = "2"; configWr["DeviceParam"]["DeviceParam"][1]["DeviceName"] = "Dev_2"; fout << configWr; fout.close();
写入后的文件内容如下:
GlobalConfig: DeviceNum: 5 DeviceParam: DeviceParam: - ID: 1 DeviceName: Dev_1 - ID: 2 DeviceName: Dev_2
注:C++写入多个数组时,使用下标直接赋值到指定参数即可。