Введение
JSON — удобный формат для хранения настроек, экспорта данных и обмена с веб-сервисами. О самом формате мы рассказывали в статье JSON: назначение, структура и особенности формата. Здесь разберём, как выполнить запись в JSON в Qt: создать объекты и массивы, собрать из них документ и сохранить его в файл. Все примеры используют стандартные классы модуля QtCore, дополнительные библиотеки не нужны.
Классы для записи JSON в Qt
QJsonObject— объект с парами «ключ — значение»;QJsonArray— массив значений;QJsonValue— одно значение: строка, число, bool, null, объект или массив;QJsonDocument— документ, который превращается в текст методомtoJson().
Простая запись в JSON: первый пример
Создадим объект с разными типами значений и массивом, а затем сохраним его в файл:
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
#include <QFile>
QJsonObject recordObject;
recordObject["Test1"] = "1";
recordObject["Test2"] = 123.4;
recordObject["Test3"] = 43;
recordObject["Test4"] = true;
recordObject["Test5"] = QString("1,2,3,4,5");
QJsonArray numbersArray;
numbersArray.append("1");
numbersArray.append("2");
numbersArray.append("3");
recordObject["Test6"] = numbersArray;
QJsonDocument doc(recordObject);
QFile file("test1.json");
if (file.open(QIODevice::WriteOnly)) {
file.write(doc.toJson(QJsonDocument::Indented));
file.close();
}
Значения можно добавлять через оператор [] или метод insert(). Преобразование через QJsonValue::fromVariant() не требуется: QJsonValue сам создаётся из строк, чисел и bool. Метод toJson() возвращает QByteArray в кодировке UTF-8, поэтому его удобно сразу записать в файл методом write().
На выходе получится файл test1.json:
{
"Test1": "1",
"Test2": 123.4,
"Test3": 43,
"Test4": true,
"Test5": "1,2,3,4,5",
"Test6": [
"1",
"2",
"3"
]
}
Вложенные объекты
Объекты можно вкладывать друг в друга. Создадим более сложный файл:
QJsonObject obj2Object;
obj2Object["Test4"] = "4";
obj2Object["Test5"] = "5";
obj2Object["Test6"] = "6";
obj2Object["Test7"] = "1";
obj2Object["Test8"] = 123.4;
obj2Object["Test9"] = 43;
obj2Object["Test10"] = true;
QJsonObject objObject;
objObject["Test1"] = "1";
objObject["Test2"] = "2";
objObject["Test3"] = "3";
objObject["Test11"] = obj2Object;
QJsonObject recordObject;
recordObject["Test12"] = objObject;
QFile file("test2.json");
if (file.open(QIODevice::WriteOnly))
file.write(QJsonDocument(recordObject).toJson());
Содержимое файла test2.json:
{
"Test12": {
"Test1": "1",
"Test11": {
"Test10": true,
"Test4": "4",
"Test5": "5",
"Test6": "6",
"Test7": "1",
"Test8": 123.4,
"Test9": 43
},
"Test2": "2",
"Test3": "3"
}
}
Обратите внимание на порядок ключей. QJsonObject хранит ключи отсортированными по алфавиту, поэтому «Test10» и «Test11» оказались раньше «Test2». Порядок, в котором вы добавляли значения, не сохраняется. Если порядок важен, храните данные в массиве.
Практический пример: сохранение настроек
Более жизненный пример — сохранение настроек окна и списка последних файлов:
void saveSettings(const QString &path, const QSize &size,
bool maximized, const QStringList &recent)
{
QJsonObject window;
window["width"] = size.width();
window["height"] = size.height();
window["maximized"] = maximized;
QJsonObject root;
root["version"] = 1;
root["window"] = window;
root["recentFiles"] = QJsonArray::fromStringList(recent);
QSaveFile file(path);
if (file.open(QIODevice::WriteOnly)) {
file.write(QJsonDocument(root).toJson());
file.commit();
}
}
Класс QSaveFile записывает данные во временный файл и заменяет оригинал только после успешного commit(). Так файл настроек не повредится, если программа завершится во время записи.
Запись массива объектов
Список структур удобно сохранять как массив объектов:
struct User { QString name; int age; bool admin; };
QJsonArray usersArray;
for (const User &u : users) {
QJsonObject obj;
obj["name"] = u.name;
obj["age"] = u.age;
obj["admin"] = u.admin;
usersArray.append(obj);
}
QJsonObject root;
root["users"] = usersArray;
Форматирование: Indented и Compact
Метод toJson() принимает формат вывода. QJsonDocument::Indented (по умолчанию) добавляет отступы и переносы строк — такой файл удобно читать и править вручную. QJsonDocument::Compact записывает всё в одну строку без пробелов. Это экономит место и подходит для передачи данных по сети.
QByteArray pretty = doc.toJson(QJsonDocument::Indented);
QByteArray compact = doc.toJson(QJsonDocument::Compact);
Проверка: чтение записанного файла
Чтобы убедиться, что данные записаны правильно, прочитайте файл обратно:
QFile file("test1.json");
if (file.open(QIODevice::ReadOnly)) {
QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
qDebug() << doc["Test2"].toDouble(); // 123.4
}
Подробнее о чтении и разборе JSON смотрите в статье Работа с JSON в Qt C++.
Заключение
Сохранение данных в формате JSON сводится к трём шагам: собрать данные в QJsonObject и QJsonArray, обернуть их в QJsonDocument и сохранить результат toJson() в файл. Для важных данных используйте QSaveFile, а если порядок элементов имеет значение, храните их в массиве, а не в объекте.