Введение
JSON — самый распространённый формат для хранения структурированных данных и обмена ими между приложениями. Если вам нужно прочитать JSON-файл или ответ от сервера в Qt, для этого есть набор классов QJsonDocument, QJsonObject, QJsonArray, QJsonValue — в этой статье разберём базовый процесс разбора JSON шаг за шагом.
Концепция
Процесс чтения JSON в Qt состоит из трёх шагов: (1) получить сырые байты JSON-текста — из файла, из сети или из строки; (2) распарсить их в QJsonDocument через QJsonDocument::fromJson(); (3) обратиться к содержимому документа как к объекту (QJsonObject, если корень JSON — {...}) или массиву (QJsonArray, если корень — [...]), и далее читать конкретные поля через .value("имя") или индекс [i].
Пример кода: Чтение JSON в Qt
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QDebug>
void readJsonFromFile()
{
QFile file("config.json");
if (!file.open(QIODevice::ReadOnly)) {
qDebug() << "Не удалось открыть файл";
return;
}
const QByteArray rawData = file.readAll();
file.close();
QJsonParseError parseError;
const QJsonDocument doc = QJsonDocument::fromJson(rawData, &parseError);
if (parseError.error != QJsonParseError::NoError) {
qDebug() << "Ошибка разбора JSON:" << parseError.errorString();
return;
}
if (!doc.isObject()) {
qDebug() << "Ожидался JSON-объект в корне файла";
return;
}
const QJsonObject obj = doc.object();
// Чтение простых полей
const QString appName = obj.value("appName").toString();
const int maxUsers = obj.value("maxUsers").toInt();
const bool debugMode = obj.value("debugMode").toBool(false); // false — значение по умолчанию
qDebug() << "Название приложения:" << appName;
qDebug() << "Максимум пользователей:" << maxUsers;
qDebug() << "Режим отладки:" << debugMode;
// Чтение вложенного объекта
if (obj.contains("server") && obj.value("server").isObject()) {
const QJsonObject serverObj = obj.value("server").toObject();
qDebug() << "Адрес сервера:" << serverObj.value("host").toString();
qDebug() << "Порт сервера:" << serverObj.value("port").toInt();
}
// Чтение массива
if (obj.contains("allowedUsers") && obj.value("allowedUsers").isArray()) {
const QJsonArray usersArray = obj.value("allowedUsers").toArray();
for (const QJsonValue &userValue : usersArray) {
qDebug() << "Разрешённый пользователь:" << userValue.toString();
}
}
}
{
"appName": "MyApp",
"maxUsers": 100,
"debugMode": true,
"server": {
"host": "192.168.1.10",
"port": 8080
},
"allowedUsers": ["alice", "bob", "charlie"]
}
Пояснения к коду
QJsonDocument::fromJson() принимает QByteArray и необязательный второй аргумент QJsonParseError, в который записывается информация об ошибке, если текст не является корректным JSON — проверка parseError.error != QJsonParseError::NoError обязательна, чтобы не продолжить работу с пустым или некорректным документом.
Метод .value("ключ") возвращает QJsonValue, который затем приводится к конкретному типу через .toString(), .toInt(), .toBool() и так далее — если ключ отсутствует в JSON, эти методы вернут «пустое» значение по умолчанию (пустую строку, 0, false), не выбрасывая исключение. Для toBool()/toInt() можно явно указать собственное значение по умолчанию вторым параметром, как показано с debugMode. Вложенные объекты читаются через .toObject(), а массивы — через .toArray() с последующим перебором в цикле for.
Подводные камни
- Отсутствие проверки
parseErrorперед использованием документа. Если JSON содержит синтаксическую ошибку (пропущенная запятая, незакрытая скобка),fromJson()вернёт пустой документ без явного исключения — без проверкиparseErrorпрограмма продолжит работу с пустыми данными, что трудно сразу диагностировать. - Обращение к полю без проверки
contains(), когда поле может отсутствовать. Хотя.value()не крашится на отсутствующем ключе, для вложенных объектов и массивов лучше явно проверятьcontains()иisObject()/isArray()перед попыткой использовать значение как объект или массив — иначе.toObject()на отсутствующем или неверном по типу значении вернёт пустой объект, и дальнейший код может работать с «пустыми» данными без явного понимания причины. - Путаница между объектом (
{...}) и массивом ([...]) в корне JSON. Если файл начинается с[, а код пытается вызватьdoc.object(), результат будет некорректным — нужно сначала проверитьdoc.isObject()/doc.isArray(), как показано в примере. - Чтение чисел с потерей точности для очень больших значений.
QJsonValue::toInt()иtoDouble()имеют свои ограничения по диапазону — для очень больших целых чисел (превышающих диапазонint) или чисел, требующих повышенной точности, нужно использоватьtoDouble()с пониманием его ограничений или хранить такие значения как строки.