nlohmann.jsonでjsonファイルをシリアライズ・デシリアライズする

もくじ
https://tera1707.com/entry/2022/02/06/144447

やりたいこと

C++のアプリで、jsonを読みたい。

人に聞いたところによると、nlohmann.jsonというライブラリがよいらしい。やってみる。

やったこと

準備

VisualStudio2022で、C++のプロジェクトを作る。

そのプロジェクトで「nugetパッケージの管理」を選んで、パッケージ管理画面を開く。

検索窓で「nlohmann」と入れると、nlohmann.jsonが出てくるので、それを選択する。

※2024/07/11時点では「3.11.2」が最新の様子。

パッケージをインストールしたら、コードに、下記のように#include <nlohmann/json.hpp>を追加する。

#include <iostream>
#include <nlohmann/json.hpp>//★コレ

int main()
{

}

そうすると、とりあえずnlohmann.jsonが使えるようになる。

jsonファイルを読み込む

まずは、下記のコードを書いて実行してみた。

#include <iostream>
#include <fstream>
#include <nlohmann/json.hpp>

int main()
{
    // ファイルからjsonを読み込み
    std::ifstream f("C:\\temp\\testjson.json");
    nlohmann::json data = nlohmann::json::parse(f);

    std::cout << "■nlohmann::json をそのまま出力" << std::endl;
    std::cout << data << std::endl;
    std::cout << "-----------------" << std::endl;

    std::cout << "■dump(4)で人間に見やすく整形して出力" << std::endl;
    std::cout << data.dump(4) << std::endl;
    std::cout << "-----------------" << std::endl;

    std::cout << "■特定の値だけを取る" << std::endl;
    std::cout << data["pi"] << std::endl;

    // std::strinとして値を取る
    std::string asStdString = data["name"].get<std::string>();

    // doubleとして値を取る
    double asDouble = data["pi"].get<double>();

    // 数値であるはずの値をstd::stringで取ろうとすると、例外が出る
    //std::string asStdStringError = data["pi"].get<std::string>();
}

出力結果

■nlohmann::json をそのまま出力
{"answer":{"everything":42},"happy":true,"list":[1,0,2],"name":"Niels","nothing":null,"object":{"currency":"USD","value":42.99},"pi":3.141}
-----------------
■dump(4)で人間に見やすく整形して出力
{
    "answer": {
        "everything": 42
    },
    "happy": true,
    "list": [
        1,
        0,
        2
    ],
    "name": "Niels",
    "nothing": null,
    "object": {
        "currency": "USD",
        "value": 42.99
    },
    "pi": 3.141
}
-----------------
■特定の値だけを取る
3.141

※↑のコードの「数値であるはずの値をstd::stringで取ろうとすると、例外が出る」の部分のコメントを外して実行すると、下記の例外が起きる。

j.type_name() の値を見ると、「number」になっている。

doubleであるべき値をstd::stringに変換しようとして、例外を起こしていると思われる。

json文字列⇔データクラスの変換

json文字列を読み込んで、データ保存用クラスに入れたり、
データ保存用クラスからjson文字列に直したりする。

下記で言うと、personクラスが、データ用クラス。

#include <iostream>
#include <fstream>
#include <nlohmann/json.hpp>

// a simple struct to model a person
struct person {
    std::string name;
    std::string address;
    int age;
};

void to_json(nlohmann::json& j, const person& p) {
    j = nlohmann::json{ {"name", p.name}, {"address", p.address}, {"age", p.age} };
}

void from_json(const nlohmann::json& j, person& p) {
    j.at("name").get_to(p.name);
    j.at("address").get_to(p.address);
    j.at("age").get_to(p.age);
}

int main()
{
    // jsonデータを入れるクラスを構築してから
    person p{ "Ned Flanders", "744 Evergreen Terrace", 60 };

    // それをjsonクラスに入れると、勝手にto_json()を実行してjsonクラスを作ってくれる
    nlohmann::json j = p;

    std::cout << j.dump() << std::endl;

    //---------------

    // jsonクラスからデータのクラスに変換(get)すると、勝手にfrom_json()を実行してデータクラスを作ってくれる
    auto p2 = j.get<person>();
}

json文字列をファイルに書き出し

作った文字列をファイルに書き込む。

#include <iostream>
#include <fstream>
#include <nlohmann/json.hpp>

// a simple struct to model a person
struct person {
    std::string name;
    std::string address;
    int age;
};

void to_json(nlohmann::json& j, const person& p) {
    j = nlohmann::json{ {"name", p.name}, {"address", p.address}, {"age", p.age} };
}

void from_json(const nlohmann::json& j, person& p) {
    j.at("name").get_to(p.name);
    j.at("address").get_to(p.address);
    j.at("age").get_to(p.age);
}

int main()
{
    // json文字列を作成
    person p{ "Ned Flanders", "744 Evergreen Terrace", 60 };
    nlohmann::json j = p;

    // ファイルに書き出し
    std::ofstream f("C:\\temp\\testoutjson.json");
    auto str = j.dump(4);
    auto len = str.length();
    f.write(str.c_str(), len);
}

参考

公式ページ

https://github.com/nlohmann/json

導入の仕方

https://json.nlohmann.me/integration/

使い方ざっくり

https://json.nlohmann.me/features/arbitrary_types/

APIリファレンス

https://json.nlohmann.me/api/basic_json/

ファイルの読み書き

https://learn.microsoft.com/ja-jp/cpp/standard-library/output-file-stream-member-functions?view=msvc-170