【C++】数据上传的方式。持久化的方式。通过 JSON,序列化与反序列化。
在 C++/CLI 或 C++/CLR 项目中,数据上传通过 JSON 是一种常见的方式。它通常需要用到 序列化 和 反序列化 处理数据,以便将数据转化为 JSON 格式(上传)或从 JSON 格式解析(下载)。
通过示例说明。
名词解释
1. 序列化(Serialization)
- 定义:
- 序列化是将内存中的对象或数据结构转换为一种格式(如 JSON、XML、二进制等),以便数据可以存储到文件、传输到网络或与其他系统交换。
- 作用:
- 将 C++ 对象(如类、结构体)转换为 JSON 格式的字符串。
- 常见用途:
- 数据上传到服务器。
- 数据持久化到文件。
2. 反序列化(Deserialization)
- 定义:
- 反序列化是序列化的逆过程,它将存储的格式化数据(如 JSON 字符串)重新解析回内存中的对象或数据结构。
- 作用:
- 将 JSON 数据(从文件或网络接收)解析为 C++ 对象。
- 常见用途:
- 从服务器接收数据。
- 读取存储的 JSON 文件,并将其转换为可操作的对象。
3. JSON(JavaScript Object Notation)
-
定义:
- JSON 是一种轻量级的数据交换格式,易于人类阅读和机器解析。
- JSON 使用键值对的形式存储数据,例如:
{ "name": "Alice", "age": 25, "isAdmin": true }
-
特点:
- 平台无关:适用于不同的编程语言(如 C++、C#、Python 等)。
- 易于解析:现代编程语言都提供了丰富的 JSON 库。
序列化与反序列化的应用
在 C++/CLI 或 C++/CLR 中,序列化和反序列化通常结合 JSON 库进行,以下实现:
1. 序列化:对象转为 JSON
示例场景:上传用户信息
将用户对象转换为 JSON 格式,上传到服务器。
示例代码:
#include <msclr/marshal_cppstd.h>
#include <nlohmann/json.hpp>
using namespace System;
// 定义一个用户对象
struct User {
std::string name;
int age;
bool isAdmin;
};
// 序列化函数
std::string SerializeUser(const User& user) {
nlohmann::json jsonObject;
jsonObject["name"] = user.name;
jsonObject["age"] = user.age;
jsonObject["isAdmin"] = user.isAdmin;
return jsonObject.dump(); //用于将 JSON 对象转换为 JSON 格式的字符串。
}
// 上传函数
void UploadUserData(User user) {
std::string jsonData = SerializeUser(user);
// 假设上传使用 C++/CLR 与托管代码交互
String^ managedJsonData = gcnew String(jsonData.c_str());
Console::WriteLine("Uploading JSON: " + managedJsonData);
// 这里可以使用 WebClient 或其他网络库发送数据到服务器
}
调用示例:
User user = {"Alice", 25, true};
UploadUserData(user);
输出结果:
Uploading JSON: {"name":"Alice","age":25,"isAdmin":true}
2. 反序列化:JSON 转为对象
示例场景:从服务器接收用户数据
从服务器接收 JSON 数据,解析为 C++ 对象。
示例代码:
#include <nlohmann/json.hpp>
// 反序列化函数
User DeserializeUser(const std::string& jsonData) {
nlohmann::json jsonObject = nlohmann::json::parse(jsonData);
User user;
user.name = jsonObject["name"].get<std::string>();
user.age = jsonObject["age"].get<int>();
user.isAdmin = jsonObject["isAdmin"].get<bool>();
return user;
}
// 模拟接收数据
void ReceiveUserData(const std::string& jsonResponse) {
User user = DeserializeUser(jsonResponse);
std::cout << "User Name: " << user.name << "\n"
<< "User Age: " << user.age << "\n"
<< "Is Admin: " << (user.isAdmin ? "Yes" : "No") << std::endl;
}
调用示例:
std::string jsonResponse = R"({"name":"Bob","age":30,"isAdmin":false})";
ReceiveUserData(jsonResponse);
输出结果:
User Name: Bob
User Age: 30
Is Admin: No
3. 使用 C++/CLI 实现与托管代码的交互
如果你需要在 C++/CLI 中操作 JSON 数据(例如与 .NET 类库交互),可以通过 marshal_as
或其他工具桥接托管字符串和非托管 JSON 处理。
示例:
#include <msclr/marshal_cppstd.h>
#include <nlohmann/json.hpp>
using namespace System;
// 定义托管接口
public ref class JsonProcessor {
public:
static String^ SerializeToJson(String^ name, int age, bool isAdmin) {
// 转换托管到非托管字符串
std::string nativeName = msclr::interop::marshal_as<std::string>(name);
// 构建 JSON
nlohmann::json jsonObject;
jsonObject["name"] = nativeName;
jsonObject["age"] = age;
jsonObject["isAdmin"] = isAdmin;
// 转换非托管字符串回托管字符串
return gcnew String(jsonObject.dump().c_str());
}
static void DeserializeFromJson(String^ json) {
// 转换托管到非托管字符串
std::string nativeJson = msclr::interop::marshal_as<std::string>(json);
// 解析 JSON
nlohmann::json jsonObject = nlohmann::json::parse(nativeJson);
// 提取数据
std::string name = jsonObject["name"].get<std::string>();
int age = jsonObject["age"].get<int>();
bool isAdmin = jsonObject["isAdmin"].get<bool>();
Console::WriteLine("Name: " + gcnew String(name.c_str()));
Console::WriteLine("Age: " + age);
Console::WriteLine("Is Admin: " + isAdmin);
}
};
调用示例(在托管环境中):
String^ json = JsonProcessor::SerializeToJson("Charlie", 28, true);
Console::WriteLine("Serialized JSON: " + json);
JsonProcessor::DeserializeFromJson(json);
输出结果:
Serialized JSON: {"name":"Charlie","age":28,"isAdmin":true}
Name: Charlie
Age: 28
Is Admin: True
小结
-
JSON 数据上传:
- 序列化:将对象转化为 JSON 格式用于传输。
- 示例:将用户对象转换为 JSON 并上传到服务器。
-
JSON 数据接收:
- 反序列化:从 JSON 格式解析为对象,用于操作。
- 示例:从服务器接收 JSON,解析用户信息。
-
C++/CLI 的作用:
- 作为桥梁连接托管和非托管代码,通过
marshal_as
或其他工具方便地实现托管与非托管字符串的转换。 - 在 .NET 环境中,可以与 JSON 库(如
nlohmann/json
或 RapidJSON)结合使用,高效处理 JSON 数据。
- 作为桥梁连接托管和非托管代码,通过