在Qt中使用JSON文件进行程序配置

发布于:2025-04-18 ⋅ 阅读:(20) ⋅ 点赞:(0)

一、常见C++中得Json库

json.org 中介绍了 JSON 在各种语言中的应用,在 C/C++ 中比较常用的JSON 库主要有以下几个:

  • JsonCpp 
    JsonCpp 是一个 C++ 用来处理 JSON 数据的开发包。 
    网址:JsonCpp

  • cJSON 
    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数据

使用QJsonDocumentQJsonObject解析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文件中,然后在运行时将其复制到外部文件中进行读写操作。


网站公告

今日签到

点亮在社区的每一天
去签到