JSON,XML,INI配置文件的区别与使用
1 配置管理
常规的应用程序在启动时通常会从配置文件中恢复数据。这些配置文件有多种不同的格式可供选择,包括 INI, XML, 和 JSON 等类型。在此文章中,我们主要关注 JSON 类型 ,这种数据交换方法具有高效简洁的特点。
1.1 JSON 格式
JSON (JavaScript Object Notation) 是一种简洁高效的轻量级数据表示方式,在编程环境中具有重要地位。它不仅便于人理解和编写代码(human-readable and writable),同时也支持快速解析与生成(fast parsing and generation)。此外,在服务器端与Web应用程序之间进行数据传输的同时,在存储配置文件管理以及数据库间的数据交互等多个方面也得到了广泛应用(widespread application in storage configuration management and database interactions)。
1.1.1 JSON 格式基本规则
数据采用键-值对的形式;
各键-值对之间可用逗号分隔;
键必须是字符串类型;
值可为:
- 字符串(需使用双引号 "" 包裹)
- 整数或浮点数值
- 布尔型数据(指定为 true 或 false)
- 方括号包裹的数组
- 花括号包裹的对象
- null
- 对象和数组可实现嵌套 :这种数据结构使得JSON能够有效地表示复杂的层次化信息。
1.1.2 JSON 格式示例
以下是一个配置文件的 JSON 格式示例
{
"com_baudrate": {
"com1": "9600",
"com2": "115200",
"com3": "4800"
},
"lever_arm_gps": {
"x": "0.1",
"y": "0.2",
"z": "0.3"
},
"lever_arm_lcp": {
"x": "0.4",
"y": "0.5",
"z": "0.6"
},
"ntrip": {
"ip": "192.168.1.1",
"port": "2101",
"username": "user",
"password": "password",
"mount_point": "mountpoint"
},
"output": {
"GPFPD_BIN": true,
"GTIMU_BIN": false,
"TEST_BIN_1": true
},
"storage_path": "/path/to/storage",
"decimal": "2"
}
1.1.3 python中JSON 解析和生成
在python中,可以使用 json 模块来解析和生成 JSON 格式的数据。
这段代码段用于以键值对形式将json数据以文件的形式保存下来;类似于C语言中的数组或结构体。
import json
def save_config_to_file(self):
"""保存配置到 JSON 文件"""
config = {
"com_baudrate": {
"com1": self.com1_baudrate_combo.currentText(),
"com2": self.com2_baudrate_combo.currentText(),
"com3": self.com3_baudrate_combo.currentText()
},
"lever_arm_gps": {
"x": self.gps_lever_arm_x.text(),
"y": self.gps_lever_arm_y.text(),
"z": self.gps_lever_arm_z.text()
},
"lever_arm_lcp": {
"x": self.lcp_lever_arm_x.text(),
"y": self.lcp_lever_arm_y.text(),
"z": self.lcp_lever_arm_z.text()
},
"ntrip": {
"ip": self.ntrip_ip.text(),
"port": self.ntrip_port.text(),
"username": self.ntrip_user.text(),
"password": self.ntrip_password.text(),
"mount_point": self.ntrip_mountpoint.text()
},
"output": {
"GPFPD_BIN": self.gpfpd_checkbox.isChecked(),
"GTIMU_BIN": self.gtimu_checkbox.isChecked(),
"TEST_BIN_1": self.testbin1_checkbox.isChecked()
},
"storage_path": self.file_path_display.text(), # 保存用户选择的存储路径
"decimal":self.decimal_input.text()
}
try:
print(f"Configuration file path: {CONFIG_FILE}")
with open(CONFIG_FILE, "w") as file:
json.dump(config, file, indent=4)
if os.path.exists(CONFIG_FILE):
print("Configuration file exists.")
else:
print("Configuration file not found.")
with open(CONFIG_FILE, "r") as file:
print(file.read())
except Exception as e:
QMessageBox.critical(self, "Error", f"Failed to save configuration: {e}")
这里加载相应的代码可以在本地文件系统中直接读取配置文件,并将设置恢复到用户界面的初始状态。可以通过与C语言兼容的方式访问类似数组结构的**config[["com_baudrate"]["com1"]]**格式来完成具体的配置管理和数据处理操作。
def load_config_from_file(self):
"""从 JSON 文件加载配置"""
if not os.path.exists(CONFIG_FILE):
return # 如果配置文件不存在,跳过加载
try:
with open(CONFIG_FILE, "r") as file:
config = json.load(file)
# 恢复串口波特率
self.com1_baudrate_combo.setCurrentText(config["com_baudrate"]["com1"])
self.com2_baudrate_combo.setCurrentText(config["com_baudrate"]["com2"])
self.com3_baudrate_combo.setCurrentText(config["com_baudrate"]["com3"])
# 恢复杠杆臂参数
self.gps_lever_arm_x.setText(config["lever_arm_gps"]["x"])
self.gps_lever_arm_y.setText(config["lever_arm_gps"]["y"])
self.gps_lever_arm_z.setText(config["lever_arm_gps"]["z"])
self.lcp_lever_arm_x.setText(config["lever_arm_lcp"]["x"])
self.lcp_lever_arm_y.setText(config["lever_arm_lcp"]["y"])
self.lcp_lever_arm_z.setText(config["lever_arm_lcp"]["z"])
# 恢复 NTRIP 配置
self.ntrip_ip.setText(config["ntrip"]["ip"])
self.ntrip_port.setText(config["ntrip"]["port"])
self.ntrip_user.setText(config["ntrip"]["username"])
self.ntrip_password.setText(config["ntrip"]["password"])
self.ntrip_mountpoint.setText(config["ntrip"]["mount_point"])
# 恢复输出设置
self.gpfpd_checkbox.setChecked(config["output"]["GPFPD_BIN"])
self.gtimu_checkbox.setChecked(config["output"]["GTIMU_BIN"])
self.testbin1_checkbox.setChecked(config["output"]["TEST_BIN_1"])
# 恢复存储路径
if "storage_path" in config:
self.file_path_display.setText(config["storage_path"])
if "decimal" in config:
self.decimal_input.setText(config["decimal"])
print("Configuration loaded successfully.")
except Exception as e:
QMessageBox.critical(self, "Error", f"Failed to load configuration: {e}")
1.1.4 c++中JSON 解析和生成
C++同样提供了一系列现成的模块,在本次示例中我们采用的是QT平台下的JSON格式处理功能。具体实例是通过QJsonDocument类来完成JSON数据的解析,并生成相应的数据结构。
MODBUS寄存器及其地址的具体实现可以通过将MODBUS寄存器的数据以文件形式存储,并采用特定的方式进行读取与修改操作。
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
void ConfigManager::saveModbusRegistersToJson(const QVector<QPair<int, QString>> ®isters) {
// 创建一个 JSON 数组,用来存放所有 Modbus 寄存器数据
QJsonArray jsonArray;
// 遍历传入的寄存器列表,将每个寄存器的数据转换为 JSON 对象,并添加到 JSON 数组中
for (const auto ® : registers) {
QJsonObject jsonObj;
// 将寄存器的地址(整数类型)和名称(字符串类型)添加到 JSON 对象中
jsonObj["address"] = reg.first; // 寄存器的地址
jsonObj["name"] = reg.second; // 寄存器的名称
// 将这个 JSON 对象添加到 JSON 数组中
jsonArray.append(jsonObj);
}
// 创建根 JSON 对象
QJsonObject rootObj;
rootObj["ModbusRegisters"] = jsonArray;
// 创建 QJsonDocument 对象来保存 JSON 数据
QJsonDocument jsonDoc(rootObj);
QFile file("modbus_registers.json");
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
file.write(jsonDoc.toJson());
file.close();成功
} else {
qDebug() << "Failed to save Modbus registers to JSON file.";
}
}
这段代码的主要功能是类似于封装与解封装的过程来处理JSON数据。
QVector<QPair<int, QString>> ConfigManager::loadModbusRegistersFromJson() {
QVector<QPair<int, QString>> registers;
QFile file("modbus_registers.json");
if (!file.exists()) {
qDebug() << "JSON file not found, returning empty register list.";
return registers;
}
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QByteArray jsonData = file.readAll();
file.close();
// 创建 QJsonDocument 对象来解析 JSON 数据
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData);
if (jsonDoc.isObject()) {
// 获取根 JSON 对象
QJsonObject rootObj = jsonDoc.object();
// 获取 Modbus 寄存器数组
if (rootObj.contains("ModbusRegisters") && rootObj["ModbusRegisters"].isArray()) {
// 遍历 Modbus 寄存器数组,将每个 JSON 对象转换为 QPair<int, QString> 类型,并添加到列表中
QJsonArray jsonArray = rootObj["ModbusRegisters"].toArray();
for (const QJsonValue &value : jsonArray) {
if (value.isObject()) {
QJsonObject jsonObj = value.toObject();
int address = jsonObj["address"].toInt();
QString name = jsonObj["name"].toString();
registers.append(qMakePair(address, name));
}
}
}
} else {
qDebug() << "Invalid JSON format in file.";
}
} else {
qDebug() << "Failed to open JSON file for reading.";
}
qDebug() << "Modbus registers loaded from JSON file:" << registers;
return registers;
}
在进行JSON解析与生成的过程中,Python与C++的基本流程是相同的。主要区别在于Python使用标准库中的json模块实现这一功能(如json.dump用于序列化数据),而C++则通过类库(如QJsonDocument)来完成JSON对象的操作。相比之下,在实现复杂性方面Python显得更为简洁高效。具体的步骤包括先将数据格式化为字符串形式(如JSON字符串),然后调用相应的库函数对其进行序列化(dump)或反序列化(load)。而对于C++,由于其语法复杂性和对底层资源的控制能力更强,通常开发者需要自行编写代码来处理JSON文件的具体读取、解析以及生成过程。
1.1.5 C与JSON
在C语言中有一种轻量化的CJSON库被广泛应用于解析与生成JSON数据这一过程上。此外在C编程中倾向于用于微控制器的情况下内存占用受到严格限制这种情况下最有效的策略是将JSON格式解析后转换为结构体对象后再进行操作
1.2 INI 格式
INI (Initialization File) 是 Windows 系统中常用的配置文件格式。
一种常见的简单文件格式,在编程中容易理解和编写代码,并且方便机器解析与生成数据。
它主要应用于Windows系统中的注册表管理功能,并且在实际应用中还广泛用于存储配置信息以及数据库之间的数据交换场景。
pip install some-package -i https://pypi.tuna.tsinghua.edu.cn/simple
1.3 XML 格式
XML 被视为一种标记语言,并被选定为国际标准组织选定的标准通用标记语言。它是一种结构化标记语言,在技术领域中具有易于人机两方面理解与编写的特点,并具有机器解析与生成的能力。XML 被广泛用于存储和交换不同形式的数据信息包括电子邮件、网页内容、系统配置参数以及附加元数据等
在QT中,使用到XML的地方主要是Qt做语言翻译的.ts文件。
JSON在实际应用中通常被广泛应用于需要处理复杂数据结构的转换与配置管理场景。而INI文件则主要用于存储一些简单的配置项及其维护工作。目前来看,在ts项目中XML主要用于特定场景的应用,但在其他地方并未见到有实际应用案例。
