Работа с JSON в C++: парсинг и сериализация данных

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение в работу с JSON в C++

JSON (JavaScript Object Notation) — это легкий формат обмена данными, который широко используется в веб-разработке, конфигурационных файлах и API-интерфейсах. Несмотря на то, что C++ не имеет встроенной поддержки JSON, существует множество надежных библиотек, которые упрощают парсинг (разбор) и сериализацию (преобразование в строку) данных. В этой статье мы рассмотрим две популярные библиотеки: nlohmann/json (рекомендуется для новичков и современных проектов) и Boost.PropertyTree (для тех, кто уже использует Boost). Вы узнаете, как читать, создавать, изменять и выводить JSON-данные на C++.

Библиотека nlohmann/json: установка и базовые принципы

Библиотека nlohmann/json (часто называется "JSON for Modern C++") является одной из самых популярных благодаря своей простоте и интуитивно понятному API. Она поддерживает C++11 и выше, не требует внешних зависимостей и распространяется как один заголовочный файл json.hpp.

Установка

Скачайте файл json.hpp с GitHub-репозитория и поместите его в папку с вашим проектом. Затем подключите его в коде:

#include <iostream>
#include <fstream>
#include "json.hpp" // Подключение библиотеки

using json = nlohmann::json;

Парсинг JSON из строки и файла

Библиотека позволяет парсить JSON из строки, файла или потока ввода. Рассмотрим пример парсинга из строки:

#include <iostream>
#include "json.hpp"

using json = nlohmann::json;

int main() {
    // Строка JSON
    std::string jsonString = R"({
        "name": "Alice",
        "age": 30,
        "isStudent": false,
        "hobbies": ["reading", "coding"]
    })";
    
    // Парсинг
    json data = json::parse(jsonString);
    
    // Доступ к данным
    std::cout << "Name: " << data["name"] << std::endl;
    std::cout << "Age: " << data["age"] << std::endl;
    std::cout << "Is student: " << (data["isStudent"] ? "true" : "false") << std::endl;
    
    // Итерация по массиву
    for (auto& hobby : data["hobbies"]) {
        std::cout << "Hobby: " << hobby << std::endl;
    }
    
    return 0;
}

Для парсинга из файла используйте json::parse(std::ifstream("data.json"));.

Сериализация JSON

Создание JSON-объекта и его сериализация в строку выполняется естественным образом:

#include <iostream>
#include "json.hpp"

using json = nlohmann::json;

int main() {
    json person;
    person["name"] = "Bob";
    person["age"] = 25;
    person["isStudent"] = true;
    person["hobbies"] = {"gaming", "swimming"};
    
    // Вложенный объект
    json address;
    address["city"] = "Moscow";
    address["street"] = "Tverskaya";
    person["address"] = address;
    
    // Сериализация в строку с отступами
    std::string serialized = person.dump(4); // 4 пробела для форматирования
    std::cout << serialized << std::endl;
    
    // Сохранение в файл
    std::ofstream file("output.json");
    file << person.dump(2);
    file.close();
    
    return 0;
}

Метод dump() преобразует объект в строку. Параметр указывает количество пробелов для отступов (0 — компактный вывод).

Библиотека Boost.PropertyTree: альтернативный подход

Если в вашем проекте уже используется Boost, библиотека Boost.PropertyTree предоставляет удобный способ работы с JSON и другими форматами (XML, INI). Она менее специализирована для JSON, но хорошо интегрируется с экосистемой Boost.

Парсинг JSON с Boost.PropertyTree

#include <iostream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

int main() {
    using boost::property_tree::ptree;
    
    ptree pt;
    // Чтение из файла
    boost::property_tree::read_json("config.json", pt);
    
    // Доступ к значениям
    std::string name = pt.get<std::string>("name");
    int age = pt.get<int>("age");
    
    std::cout << "Name: " << name << std::endl;
    std::cout << "Age: " << age << std::endl;
    
    // Обход массива (в JSON представлен как объект с числовыми ключами)
    for (auto& item : pt.get_child("hobbies")) {
        std::cout << "Hobby: " << item.second.data() << std::endl;
    }
    
    return 0;
}

Обратите внимание: массивы в Boost.PropertyTree хранятся как объекты с ключами "0", "1", "2" и т.д. Это необходимо учитывать при работе с JSON-массивами.

Сериализация с Boost.PropertyTree

#include <iostream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

int main() {
    using boost::property_tree::ptree;
    
    ptree pt;
    pt.put("name", "Charlie");
    pt.put("age", 35);
    
    // Создание массива
    ptree hobbies;
    hobbies.put("0", "running");
    hobbies.put("1", "cycling");
    pt.add_child("hobbies", hobbies);
    
    // Запись в файл
    boost::property_tree::write_json("output_boost.json", pt);
    
    // Вывод в поток
    std::ostringstream oss;
    boost::property_tree::write_json(oss, pt);
    std::cout << oss.str() << std::endl;
    
    return 0;
}

Продвинутые техники: ошибки, производительность и типы данных

Обработка ошибок парсинга

При работе с внешними данными важно корректно обрабатывать ошибки. В nlohmann/json используется исключение json::parse_error:

try {
    json data                

Блоги

Рекомендаций по книгам