Qt Json 序列化操作

cpp 复制代码
#ifndef UTILS_JSON_H
#define UTILS_JSON_H

#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonValue>
#include <QFile>
#include <QVariant>
#include <QString>
#include <functional>
#include <cstddef>
#include <QSaveFile>
#include <type_traits>
#include <algorithm> // for std::min if needed, though qMin is Qt

namespace Utils {
    namespace JsonSerialize {

        // --- 数组转换 ---

        template< typename T, std::size_t N >
        inline QJsonArray ToJsonArray(const T(&arr)[N]) {
            QJsonArray result;
            for (std::size_t i = 0; i < N; ++i) {
                result.append(QJsonValue(arr[i]));
            }
            return result;
        }

        template<typename T, std::size_t N>
        inline void FromJsonArray(const QJsonArray& jarr, T(&arr)[N]) {
            const int len = std::min(static_cast<int>(jarr.size()), static_cast<int>(N));
            for (int i = 0; i < len; ++i) {
                arr[i] = static_cast<T>(jarr[i].toDouble());
            }
        }

        template <std::size_t N>
        inline void FromJsonArray(const QJsonArray& jarr, int(&arr)[N]) {
            const int len = std::min(static_cast<int>(N), jarr.size());
            for (int i = 0; i < len; ++i)
                arr[i] = jarr[i].toInt();
        }

        // --- 基础类型 jsonField (Write) ---

        inline void jsonField(QJsonObject& obj, const char* key, int val) {
            obj[key] = val;
        }
        inline void jsonField(QJsonObject& obj, const char* key, float val) {
            obj[key] = static_cast<double>(val);
        }
        inline void jsonField(QJsonObject& obj, const char* key, bool val) {
            obj[key] = val;
        }
        inline void jsonField(QJsonObject& obj, const char* key, unsigned char val) {
            obj[key] = static_cast<int>(val);
        }
        template <typename T, std::size_t N>
        inline void jsonField(QJsonObject& obj, const char* key, const T(&arr)[N]) {
            obj[key] = ToJsonArray(arr);
        }

        // --- 基础类型 jsonField (Read) ---

        inline void jsonField(const QJsonObject& obj, const char* key, int& val) {
            if (obj.contains(key)) val = obj[key].toInt();
        }
        inline void jsonField(const QJsonObject& obj, const char* key, float& val) {
            if (obj.contains(key)) val = static_cast<float>(obj[key].toDouble());
        }
        inline void jsonField(const QJsonObject& obj, const char* key, bool& val) {
            if (obj.contains(key)) val = obj[key].toBool();
        }
        inline void jsonField(const QJsonObject& obj, const char* key, unsigned char& val) {
            if (obj.contains(key)) val = static_cast<unsigned char>(obj[key].toInt());
        }
        template <typename T, std::size_t N>
        inline void jsonField(const QJsonObject& obj, const char* key, T(&arr)[N]) {
            if (obj.contains(key)) FromJsonArray(obj[key].toArray(), arr);
        }

        // --- 辅助宏 ---

        /**
         * @brief 安全地去除 m_ 前缀
         */
        inline const char* StripM_(const char* s) {
            if (!s) return s;
            // 检查 "m_" 前缀
            if (s[0] == 'm' && s[1] == '_') {
                return s + 2;
            }
            return s;
        }

        /**
         * @brief 字段宏:依赖上下文中的 obj (QJsonObject) 和 p (Struct&)
         */
        #define JF(member) jsonField(obj, StripM_(#member), p.member);

        /**
         * @brief 嵌套对象支持宏
         */
        #define JSON_NESTED(Type)                                                      \
          inline void jsonField(QJsonObject &obj, const char *key, const Type &val) {  \
            obj[key] = ToJson(val);                                                    \
          }                                                                            \
          inline void jsonField(const QJsonObject &obj, const char *key, Type &val) {  \
            if (obj.contains(key))                                                     \
              FromJson(obj[key].toObject(), val);                                      \
          }

        /**
         * @brief 定义序列化/反序列化函数
         */
        #define DEFINE_JSON(Type, ...)                                                 \
          inline QJsonObject ToJson(const Type &p) {                                   \
            QJsonObject obj;                                                           \
            __VA_ARGS__                                                                \
            return obj;                                                                \
          }                                                                            \
          inline void FromJson(const QJsonObject &obj, Type &p) {                      \
            __VA_ARGS__                                                                \
          }                                                                            \
          JSON_NESTED(Type)

        // --- SFINAE 检测 ---

        template <typename T, typename = void>
        struct has_to_json : std::false_type {};

        template<typename T>
        struct has_to_json<T, std::void_t< decltype(ToJson(std::declval<const T&>())) >> : std::true_type {};

        template<typename T>
        constexpr bool has_to_json_v = has_to_json<T>::value;

        template <typename T, typename = void>
        struct has_from_json : std::false_type {};

        template<typename T>
        struct has_from_json<T, std::void_t< decltype(FromJson(std::declval<const QJsonObject&>(), std::declval<T&>())) >> : std::true_type {};

        template<typename T>
        constexpr bool has_from_json_v = has_from_json<T>::value;

        // --- 文件 IO ---

        template <typename T, std::enable_if_t<has_to_json_v<T>, int> = 0>
        bool SaveToFile(const T& obj, const QString& filepath) {
            QSaveFile file(filepath);
            if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
                return false;
            }
            QJsonDocument doc(ToJson(obj));
            qint64 written = file.write(doc.toJson(QJsonDocument::Indented));
            if (!file.commit()) {
                return false;
            }
            return written > 0;
        }

        template <typename T, std::enable_if_t<has_from_json_v<T>, int> = 0>
        bool LoadFromFile(T& param, const QString& filePath) {
            QFile file(filePath);
            if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
                return false;

            QByteArray raw = file.readAll();
            file.close();

            if (raw.isEmpty()) {
                return false;
            }

            QJsonParseError err;
            QJsonDocument doc = QJsonDocument::fromJson(raw, &err);
            if (err.error != QJsonParseError::NoError || !doc.isObject())
                return false;

            FromJson(doc.object(), param);
            return true;
        }

    } // namespace JsonSerialize
} // namespace Utils

#endif // UTILS_JSON_H

用法

cpp 复制代码
using namespace Utils::JsonSerialize;

struct ArrT {
    int m_size = 0;
    int m_data = 0;
};

//// 生成 ArrT 的序列化代码
DEFINE_JSON(ArrT,
    JF(m_size)
    JF(m_data)
)

// ============================================================================
// 主函数
// ============================================================================
#include <QCoreApplication>
int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    qDebug() << "--- JSON Serialization Test ---";

    // 1. 创建测试对象
    ArrT myArr;
    myArr.m_size = 100;
    myArr.m_data = 200;

    QString testFilePath = "test_config.json";

    // 2. 保存到文件
    if (Utils::JsonSerialize::SaveToFile(myArr, testFilePath)) {
        qDebug() << "Success: Saved to" << testFilePath;
    } else {
        qWarning() << "Error: Failed to save file";
    }

    // 3. 从文件加载
    ArrT loadedArr;
    if (Utils::JsonSerialize::LoadFromFile(loadedArr, testFilePath)) {
        qDebug() << "Success: Loaded from file";
        qDebug() << "  Size:" << loadedArr.m_size;
        qDebug() << "  Data:" << loadedArr.m_data;
    } else {
        qWarning() << "Error: Failed to load file";
    }

    // 4. 启动 Qt 事件循环 (使用 exec 而不是 run)
    return app.exec();
}
相关推荐
平常心的技术小牛1 小时前
Qt-快速上手-QFileDialog
windows·qt·microsoft
xieliyu.1 小时前
MySQL 进阶笔记:用户 / 会话 / 全局 / 局部变量 + CASE 分支语法
开发语言·数据库·笔记·mysql
格林威1 小时前
C#高位深相机图像保存:12位16位图像保存方案,OpenCvSharp和Halcon实现
开发语言·人工智能·数码相机·计算机视觉·c#·视觉检测·工业相机
小小龙学IT1 小时前
Qt Graphics View Framework(图形视图框架)深度解析:从 Scene/View/Item 到工业级 2D 场景
开发语言·数据库·qt
程与留1 小时前
09_Qt 布局管理系统——QHBoxLayout、QVBoxLayout、QGridLayout
c++·qt
神仙别闹1 小时前
基于QT(C++)实现旅游线路规划系统
c++·qt·旅游
2601_966949651 小时前
Python 量化数据质量校验:如何确保股票历史日线数据不存在缺失交易日?
开发语言·人工智能·爬虫·python·量化策略·量化·quantdash
广东帝工智能安防1 小时前
BCAS桥梁防撞预警系统五层架构深度解析:从感知层到对接层的技术实现与选型指南
开发语言·人工智能·架构·边缘计算·桥梁防撞预警系统
树码小子2 小时前
Skill的格式 & 开发语言和工具
开发语言·skill