一、常见C++中得Json库
json.org 中介绍了 JSON 在各种语言中的应用,在 C/C++ 中比较常用的JSON 库主要有以下几个:
JsonCpp
JsonCpp 是一个 C++ 用来处理 JSON 数据的开发包。
网址:JsonCppcJSON
cJSON 是一个超轻巧,携带方便,单文件,简单的可以作为 ANSI-C 标准的 JSON 解析器。
网址:http://sourceforge.net/projects/cjson/QJson
QJson 是一个基于 Qt 的开发包用来将 JSON 数据解析成 QVariant 对象,JSON 的数组将被映射为QVariantList 实例,而其他对象映射为 QVariantMap 实例。
网址:QJson
二、QT中常用Json类
1. QJsonDocument 类
QJsonDocument 类用于读和写 JSON 文档。
一个 JSON 文档可以使用 QJsonDocument::fromJson() 从基于文本的表示转化为 QJsonDocument, toJson() 则可以反向转化为文本。解析器非常快且高效,并将 JSON 转换为 Qt 使用的二进制表示。已解析文档的有效性,可以使用 !isNull() 进行查询。
如果要查询一个 JSON 文档是否包含一个数组或一个对象,使用 isArray() 和 isObject()。包含在文档中的数组或对象可以使用 array() 或 object() 检索,然后读取或操作。
也可以使用 fromBinaryData() 或 fromRawData() 从存储的二进制表示创建来 JSON 文档。
2. QJsonArray 类
QJsonArray 类封装了一个 JSON 数组。
JSON 数组是值的列表。列表可以被操作,通过从数组中插入和删除 QJsonValue 。
一个 QJsonArray 可以和一个 QVariantList 相互转换。可以使用 size() 来查询条目的数量,通过 insert() 在指定索引处插入值,removeAt() 来删除指定索引的值。
3. QJsonObject 类
QJsonObject 类封装了一个 JSON 对象。
一个 JSON 对象是一个“key/value 对”列表,key 是独一无二的字符串,value 由一个 QJsonValue 表示。
一个 QJsonObject 可以和一个 QVariantMap 相互转换。可以使用 size() 来查询“key/value 对”的数量,通过 insert() 插入“key/value 对”, remove() 删除指定的 key。
4. QJsonValue 类
QJsonValue 类封装了一个值。
JSON 中的值有 6 种基本数据类型:
- bool(QJsonValue::Bool)
- double(QJsonValue::Double)
- string(QJsonValue::String)
- array(QJsonValue::Array)
- object(QJsonValue::Object)
- null(QJsonValue::Null)
一个值可以由任何上述数据类型表示。此外,QJsonValue 有一个特殊的标记来表示未定义的值,可以使用 isUndefined() 查询。
值的类型可以通过 type() 或 isBool()、isString() 等访问函数查询。同样地,值可以通过 toBool()、toString() 等函数转化成相应的存储类型。
5. QJsonParseError 类
QJsonParseError 类用于在 JSON 解析中报告错误。
枚举 QJsonParseError::ParseError:
该枚举描述 JSON 文档在解析过程中所发生的错误类型。
常量 | 值 | 描述 |
---|---|---|
QJsonParseError::NoError | 0 | 未发生错误 |
QJsonParseError::UnterminatedObject | 1 | 对象不正确地终止以右花括号结束 |
QJsonParseError::MissingNameSeparator | 2 | 分隔不同项的逗号丢失 |
QJsonParseError::UnterminatedArray | 3 | 数组不正确地终止以右中括号结束 |
QJsonParseError::MissingValueSeparator | 4 | 对象中分割 key/value 的冒号丢失 |
QJsonParseError::IllegalValue | 5 | 值是非法的 |
QJsonParseError::TerminationByNumber | 6 | 在解析数字时,输入流结束 |
QJsonParseError::IllegalNumber | 7 | 数字格式不正确 |
QJsonParseError::IllegalEscapeSequence | 8 | 在输入时,发生一个非法转义序列 |
QJsonParseError::IllegalUTF8String | 9 | 在输入时,发生一个非法 UTF8 序列 |
QJsonParseError::UnterminatedString | 10 | 字符串不是以引号结束 |
QJsonParseError::MissingObject | 11 | 一个对象是预期的,但是不能被发现 |
QJsonParseError::DeepNesting | 12 | 对解析器来说,JSON 文档嵌套太深 |
QJsonParseError::DocumentTooLarge | 13 | 对解析器来说,JSON 文档太大 |
QJsonParseError::GarbageAtEnd | 14 | 解析的文档在末尾处包含额外的乱码 |
三、配置步骤
1. 读取JSON文件
使用QFile
打开JSON文件,并将其内容读取到QByteArray
中。
QFile file("config.json");
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug() << "无法打开文件";
return;
}
QByteArray jsonData = file.readAll();
2. 解析JSON数据
使用QJsonDocument
和QJsonObject
解析JSON数据。
QJsonParseError error;
QJsonDocument doc = QJsonDocument::fromJson(jsonData, &error);
if (error.error != QJsonParseError::NoError) {
qDebug() << "JSON解析错误:" << error.errorString();
return;
}
QJsonObject obj = doc.object();
3. 读取配置项
通过QJsonObject
访问配置项。
QString name = obj["name"].toString();
int age = obj["age"].toInt();
qDebug() << "姓名:" << name;
qDebug() << "年龄:" << age;
4. 修改配置项
如果需要修改配置项,可以直接操作QJsonObject
。
obj["name"] = "Tom";
obj["age"] = 25;
doc.setObject(obj);
5. 保存修改后的JSON文件
将修改后的QJsonDocument
写回到文件。
file.seek(0);
file.write(doc.toJson());
file.resize(file.pos());
6. 使用Qt资源系统
如果希望将JSON文件打包到可执行文件中,可以使用Qt的资源系统。
创建一个
.qrc
文件,例如myapp.qrc
,并在其中添加JSON文件:
<!DOCTYPE RCC>
<RCC version="1.0">
<qresource>
<file>config.json</file>
</qresource>
</RCC>
在
.pro
文件中添加资源文件:
RESOURCES += myapp.qrc
在程序中使用
qrc://
路径访问JSON文件:
QFile file(":/config.json");
7. 使用第三方库简化操作
可以使用如QJSONConfig
这样的第三方库来简化JSON配置文件的操作。
获取并使用
QJSONConfig
:
git clone https://github.com/zxunge/QJSONConfig.git
在项目中包含
qjsonconfig.h
,并使用其提供的接口:
QJSONConfig cfg("cfg.json");
if (cfg.empty()) {
// 初始化配置
}
cfg.setValue("key", value);
QVariant val = cfg["key"];
cfg.sync(); // 保存配置
通过以上步骤,你可以方便地使用JSON文件对Qt程序进行配置。
四、注意事项:
编译后的.qrc
文件(即打包到可执行文件中的资源文件)是无法直接修改的。这是因为资源文件在编译时会被嵌入到可执行文件中,成为其一部分,因此无法在运行时直接修改其中的内容。
如果你需要在运行时修改JSON文件中的数据,应该将JSON文件作为外部文件存储在文件系统中,而不是将其打包到.qrc
文件中。
以下是两种常见的处理方式:
1. 使用外部JSON文件(推荐)
将JSON文件放在程序的运行目录或其他指定路径中,这样可以在运行时读取和修改它。
示例代码:
// 打开外部JSON文件
QFile file("config.json");
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug() << "无法打开文件";
return;
}
// 读取并解析JSON文件
QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
QJsonObject obj = doc.object();
// 修改JSON数据
obj["name"] = "Tom";
obj["age"] = 25;
// 保存修改后的JSON文件
file.close();
file.open(QIODevice::WriteOnly | QIODevice::Text);
file.write(doc.toJson());
file.close();
这种方式的优点是可以在运行时动态修改JSON文件的内容,适合需要频繁更新配置的应用程序。
2. 使用.qrc
文件,但仅作为默认配置
如果仍然想使用.qrc
文件,可以将其作为默认配置文件。在程序启动时,将资源文件中的默认配置复制到一个外部文件中,然后对这个外部文件进行读写操作。
示例代码:
// 检查外部配置文件是否存在
QFile externalFile("config.json");
if (!externalFile.exists()) {
// 如果不存在,从资源文件中复制默认配置
QFile resourceFile(":/config.json");
if (resourceFile.open(QIODevice::ReadOnly)) {
QByteArray data = resourceFile.readAll();
resourceFile.close();
externalFile.open(QIODevice::WriteOnly);
externalFile.write(data);
externalFile.close();
}
}
// 从外部文件读取配置
QFile file("config.json");
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug() << "无法打开文件";
return;
}
QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
QJsonObject obj = doc.object();
// 修改JSON数据
obj["name"] = "Tom";
obj["age"] = 25;
// 保存修改后的JSON文件
file.close();
file.open(QIODevice::WriteOnly | QIODevice::Text);
file.write(doc.toJson());
file.close();
这种方式结合了默认配置和运行时修改的优点。程序启动时会检查外部文件是否存在,如果不存在,则从资源文件中复制默认配置。之后的所有读写操作都针对外部文件进行,从而避免了直接修改嵌入的资源文件。
3. 总结
如果需要在运行时修改JSON文件,建议直接使用外部文件。
如果需要默认配置,可以将默认配置打包到
.qrc
文件中,然后在运行时将其复制到外部文件中进行读写操作。