【自用】C++每日一读(三)
·
一、前言
/**************************设备Topology信息**************************/
void DeviceTopologyMgr::parse_device_topology()
{
// 保证多次调用, 只存在一份设备解析数据
m_topology = DeviceTopology();
const std::string filename = std::string(xbasic::get_module_path()) + "device_topology.json";
std::string content = xbasic::read_data_from_json_file(filename);
if (content.empty()) {
xbasic::debug_output("DeviceTopologyMgr::parse_device_topology() get json content failed\n");
return;
}
cjson_object js_root(content);
// 1、解析顶层字段信息
if (!js_root.get("version", m_topology.version)) { // 非关键信息, 无需返回
xbasic::debug_output("DeviceTopologyMgr::parse_device_topology() version was not existed\n");
}
if (!js_root.get("product_type", m_topology.product_type)) {
xbasic::debug_output("DeviceTopologyMgr::parse_device_topology() product_type was not existed\n");
return;
}
if (!js_root.get("device_name", m_topology.device_name)) {
xbasic::debug_output("DeviceTopologyMgr::parse_device_topology() device_name was not existed\n");
return;
}
if (!js_root.get("datatag_file", m_topology.datatag_file)) {
xbasic::debug_output("DeviceTopologyMgr::parse_device_topology() datatag_file was not existed\n");
return;
}
// 1.1、解析板级协议数据
BoardDataTagMgr* board_tag_mgr = BoardDataTagMgr::get_instance();
board_tag_mgr->setFileName(m_topology.datatag_file);
// 1.2、解析升级信息
UpgradeTopologyMgr* upgrade_mgr = UpgradeTopologyMgr::get_instance();
upgrade_mgr->parse_upgrade_config();
// 1.3、解析版本查询信息
VersionInfoMgr* version_mgr = VersionInfoMgr::get_instance();
version_mgr->parse_system_version_config();
// 2、解析device_config数组
cjson_object device_config_arr = js_root["device_config"];
int device_config_num = device_config_arr.get_array_size();
xbasic::debug_output("DeviceTopologyMgr::parse_device_topology() device_config num=%d\n", device_config_num);
parse_device_config_info(device_config_arr, device_config_num);
// 3、解析device_config数组
cjson_object communication_config = js_root["communication"];
int communication_config_num = communication_config.get_array_size();
xbasic::debug_output("DeviceTopologyMgr::parse_device_topology() communication num=%d\n", communication_config_num);
parse_communication_config_info(communication_config, communication_config_num);
// 4、解析devices数组
cjson_object devices_arr = js_root["devices"];
int devices_num = devices_arr.get_array_size();
xbasic::debug_output("DeviceTopologyMgr::parse_device_topology() devices num=%d\n", devices_num);
parse_devices_info(devices_arr, devices_num);
return;
}
这段 parse_device_topology() 函数截取自实际项目代码,是一个设备拓扑配置文件的解析入口,干的事就是:
- 从程序目录里读
device_topology.json配置文件 - 把JSON里的各种配置(版本、设备、通信协议等)解析出来,存到内存里的
m_topology对象 - 再调用其他管理器,继续解析协议、升级、版本、设备列表这些子配置
二、逐段拆解
1. 初始化和读取JSON文件
// 保证多次调用,只存在一份设备解析数据
m_topology = DeviceTopology();
// 1. 拼接配置文件路径:程序当前目录 + "device_topology.json"
const std::string filename = std::string(xbasic::get_module_path()) + "device_topology.json";
// 2. 读取JSON文件内容
std::string content = xbasic::read_data_from_json_file(filename);
// 如果文件读失败/内容为空,打日志直接返回
if (content.empty()) {
xbasic::debug_output("... get json content failed\n");
return;
}
- 这里的
get_module_path(),是自己实现的函数:拿到程序当前目录,用于拼接配置文件名 read_data_from_json_file把JSON文件的内容读到content字符串里,读失败就直接退出
2. 解析JSON根节点的基础信息
// 把字符串解析成cJSON对象(假设是封装好的JSON解析器)
cjson_object js_root(content);
// 解析version字段(非关键,不存在也不返回,只是打日志)
if (!js_root.get("version", m_topology.version)) {
xbasic::debug_output("... version was not existed\n");
}
// 解析product_type(必须存在,否则返回)
if (!js_root.get("product_type", m_topology.product_type)) {
xbasic::debug_output("... product_type was not existed\n");
return;
}
// 解析device_name(必须存在)
if (!js_root.get("device_name", m_topology.device_name)) {
return;
}
// 解析datatag_file(必须存在,这是后面协议解析要用的文件)
if (!js_root.get("datatag_file", m_topology.datatag_file)) {
return;
}
- 从JSON的根节点,把
version、product_type、device_name、datatag_file这些基础信息读出来,存到m_topology对象里 - 除了
version,其他几个字段是必须的,不存在就直接退出解析
3. 调用其他管理器,解析子配置
// 1.1 解析板级协议数据:用BoardDataTagMgr,解析datatag_file里的协议配置
BoardDataTagMgr* board_tag_mgr = BoardDataTagMgr::get_instance();
board_tag_mgr->setFileName(m_topology.datatag_file);
// 1.2 解析升级信息:调用UpgradeTopologyMgr解析升级配置
UpgradeTopologyMgr* upgrade_mgr = UpgradeTopologyMgr::get_instance();
upgrade_mgr->parse_upgrade_config();
// 1.3 解析版本查询信息:调用VersionInfoMgr解析系统版本配置
VersionInfoMgr* version_mgr = VersionInfoMgr::get_instance();
version_mgr->parse_system_version_config();
- 这里用到了单例模式,
get_instance()拿到每个管理器的唯一实例 - 把前面读到的
datatag_file传给协议管理器,让它继续解析协议配置 - 升级、版本这些模块也有自己的解析函数,各自处理自己的配置
4. 解析JSON里的数组配置
// 2. 解析device_config数组(设备配置)
cjson_object device_config_arr = js_root["device_config"];
int device_config_num = device_config_arr.get_array_size();
xbasic::debug_output("... device_config num=%d\n", device_config_num);
parse_device_config_info(device_config_arr, device_config_num);
// 3. 解析communication_config数组(通信配置)
cjson_object communication_config = js_root["communication"];
int communication_config_num = communication_config.get_array_size();
xbasic::debug_output("... communication num=%d\n", communication_config_num);
parse_communication_config_info(communication_config, communication_config_num);
// 4. 解析devices数组(设备列表)
cjson_object devices_arr = js_root["devices"];
int devices_num = devices_arr.get_array_size();
xbasic::debug_output("... devices num=%d\n", devices_num);
parse_devices_info(devices_arr, devices_num);
- 从JSON里读取
device_config、communication、devices这几个数组 - 分别调用对应的解析函数,把数组里的每一项解析出来,存到对应的配置里
- 比如
parse_devices_info会遍历devices数组,把每个设备的配置存到内存里
三、整体“流程图”
parse_device_topology()
├─ 1. 初始化m_topology,重置数据
├─ 2. 读入device_topology.json文件
│ └─ 读失败 → 直接返回
├─ 3. 解析JSON根节点基础字段
│ ├─ version(可选)
│ ├─ product_type(必须)
│ ├─ device_name(必须)
│ └─ datatag_file(必须)
├─ 4. 调用其他管理器解析子配置
│ ├─ BoardDataTagMgr(解析协议文件)
│ ├─ UpgradeTopologyMgr(解析升级配置)
│ └─ VersionInfoMgr(解析版本配置)
├─ 5. 解析JSON里的数组配置
│ ├─ device_config数组 → parse_device_config_info
│ ├─ communication数组 → parse_communication_config_info
│ └─ devices数组 → parse_devices_info
└─ 解析完成,所有配置都存到内存里了
四、关键设计思想
- 模块化拆分:把不同类型的配置(设备、通信、协议、升级、版本)交给不同的管理器处理,每个管理器只负责自己的部分,职责清晰
- 分阶段解析:先读基础配置,再读子配置,最后读数组配置,依赖关系明确(比如协议管理器需要先拿到
datatag_file路径) - 错误处理:关键配置不存在就直接返回,避免后续解析出现更严重的错误
- 日志辅助:每个关键步骤都打日志,方便排查问题(比如配置文件不存在、数组大小是0等)
五、举个直观的JSON结构例子
你可以想象 device_topology.json 大概长这样:
{
"version": "1.0.0",
"product_type": "industrial_controller",
"device_name": "main_controller",
"datatag_file": "board_tag.json",
"device_config": [
{"id": 1, "name": "sensor1", "type": "input"},
{"id": 2, "name": "relay1", "type": "output"}
],
"communication": [
{"type": "serial", "baudrate": 9600},
{"type": "ethernet", "ip": "192.168.1.100"}
],
"devices": [
{"id": 1, "name": "temperature_sensor", "address": 0x01},
{"id": 2, "name": "pressure_sensor", "address": 0x02}
]
}
这段代码就是把这个JSON里的所有信息,全部解析到程序的内存对象里,供后面的业务逻辑使用。
更多推荐



所有评论(0)