成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

別再被序列化搞懵了!用人話告訴你 C++ 里 JSON 和 ProtoBuf 到底咋玩

開發
今天咱們來聊聊一個聽起來很高大上,但其實超級實用的話題——C++序列化。

今天咱們來聊聊一個聽起來很高大上,但其實超級實用的話題——C++序列化。

先別慌,我知道你現在腦子里可能有好幾個問題:

  • 序列化是個啥玩意兒?
  • JSON不是前端的東西嗎?
  • ProtoBuf又是什么鬼?
  • 它們倆誰更厲害?

別著急,今天我就用最接地氣的話給你掰扯明白。保證看完之后,你不僅知道這些是什么,還能上手寫代碼!

一、序列化到底是啥?先來個生活化的理解

想象一下,你要給遠方的朋友寄一個玩具汽車。你能直接把汽車扔進郵筒嗎?當然不行!你得先把它拆開,放進盒子里,貼上標簽,這樣郵遞員才能送到朋友那里。朋友收到后,再按照說明書把汽車重新組裝起來。

這個過程就是序列化!

  • 拆車裝盒 = 序列化(把內存中的對象轉換成可傳輸的格式)
  • 重新組裝 = 反序列化(把傳輸格式還原成內存中的對象)

在編程世界里,我們經常需要:

  • 把數據存到文件里
  • 通過網絡發送數據
  • 在不同程序間傳遞信息

這時候就需要序列化了!因為內存里的對象就像那個玩具汽車,不能直接"郵寄"。

二、JSON:網紅選手,人見人愛

1. JSON是什么?

JSON全稱是JavaScript Object Notation,但別被名字騙了,它早就不是 JavaScript 的專利了。現在幾乎所有編程語言都支持JSON,因為它有個超大的優點:人類看得懂!

看看這個例子:

{
  "name": "張三",
  "age": 25,
  "city": "北京",
  "hobbies": ["游戲", "電影", "音樂"]
}

是不是一眼就看明白了?這就是JSON的魅力,連你奶奶都能看懂(好吧,可能有點夸張)。

22. C++怎么玩JSON?

C++本身不支持JSON,但有很多優秀的庫。我推薦用nlohmann/json,因為它用起來就像喝水一樣簡單。

首先,咱們看看怎么把C++對象變成JSON:

#include <nlohmann/json.hpp>
#include <iostream>
#include <string>
#include <vector>

using json = nlohmann::json;
using namespace std;

// 定義一個人的結構體
struct Person {
    string name;
    int age;
    string city;
    vector<string> hobbies;
};

int main() {
    // 創建一個人
    Person p = {"張三", 25, "北京", {"游戲", "電影", "音樂"}};
    
    // 序列化:把對象變成JSON
    json j;
    j["name"] = p.name;
    j["age"] = p.age;
    j["city"] = p.city;
    j["hobbies"] = p.hobbies;
    
    // 輸出JSON字符串
    cout << "序列化結果:" << endl;
    cout << j.dump(4) << endl;  // 4表示縮進4個空格,好看一些
    
    return 0;
}

// 編譯命令:g++ -o test test.cpp

運行結果:

序列化結果:
{
    "age": 25,
    "city": "北京",
    "hobbies": [
        "游戲",
        "電影",
        "音樂"
    ],
    "name": "張三"
}

再看看反序列化,把JSON變回對象:

#include <nlohmann/json.hpp>
#include <iostream>
#include <string>
#include <vector>

using json = nlohmann::json;
using namespace std;

struct Person {
    string name;
    int age;
    string city;
    vector<string> hobbies;
    
    // 方便輸出的函數
    void print() {
        cout << "姓名: " << name << endl;
        cout << "年齡: " << age << endl;
        cout << "城市: " << city << endl;
        cout << "愛好: ";
        for(const auto& hobby : hobbies) {
            cout << hobby << " ";
        }
        cout << endl;
    }
};

int main() {
    // 假設這是從網絡或文件讀取的JSON字符串
    string json_str = R"({
        "name": "李四",
        "age": 30,
        "city": "上海",
        "hobbies": ["讀書", "旅游", "攝影"]
    })";
    
    // 反序列化:把JSON變成對象
    json j = json::parse(json_str);
    
    Person p;
    p.name = j["name"].get<string>();           // 顯式轉換為string
    p.age = j["age"].get<int>();               // 顯式轉換為int
    p.city = j["city"].get<string>();          // 顯式轉換為string
    p.hobbies = j["hobbies"].get<vector<string>>(); // 顯式轉換為vector<string>
    
    cout << "反序列化結果:" << endl;
    p.print();
    
    return 0;
}

// 編譯命令:g++ -o test test.cpp

運行結果:

反序列化結果:
姓名: 李四
年齡: 30
城市: 上海
愛好: 讀書 旅游 攝影

3. JSON的優缺點

優點:

  • 人類可讀,調試超方便
  • 支持的語言多,幾乎通用
  • 語法簡單,學習成本低
  • Web開發的標配

缺點:

  • 體積比較大(因為要存儲字段名)
  • 解析速度相對較慢
  • 不支持二進制數據
  • 沒有數據類型驗證

三、ProtoBuf:性能怪獸,Google出品

1. ProtoBuf是個啥?

Protocol Buffers(簡稱ProtoBuf)是Google開發的序列化協議。如果說 JSON 是個顏值擔當,那 ProtoBuf 就是個實力派。它的特點就是:快!小!強!

但有個小缺點:人類看不懂。序列化后的數據是二進制的,就像這樣:

\x08\x96\x01\x12\x04\xE5\xBC\xA0\xE4\xB8\x89\x1A\x06\xE5\x8C\x97\xE4\xBA\xAC...

看懵了吧?這就是為什么它快的原因——計算機處理二進制比處理文本快多了。

2. ProtoBuf怎么用?

使用ProtoBuf需要先定義一個.proto文件,描述數據結構:

// person.proto
syntax = "proto3";

message Person {
    string name = 1;
    int32 age = 2;
    string city = 3;
    repeated string hobbies = 4;
}

然后用protoc編譯器生成C++代碼:

protoc --cpp_out=. person.proto

這會生成person.pb.h和person.pb.cc文件。

接下來就能在C++里用了:

#include <iostream>
#include <fstream>
#include "person.pb.h"

using namespace std;

int main() {
    // 創建Person對象
    Person person;
    person.set_name("王五");
    person.set_age(28);
    person.set_city("深圳");
    person.add_hobbies("編程");
    person.add_hobbies("健身");
    person.add_hobbies("美食");
    
    // 序列化到字符串
    string serialized_data;
    person.SerializeToString(&serialized_data);
    
    cout << "序列化完成,數據大小: " << serialized_data.size() << " 字節" << endl;
    
    // 模擬網絡傳輸或文件存儲...
    
    // 反序列化
    Person new_person;
    new_person.ParseFromString(serialized_data);
    
    cout << "反序列化結果:" << endl;
    cout << "姓名: " << new_person.name() << endl;
    cout << "年齡: " << new_person.age() << endl;
    cout << "城市: " << new_person.city() << endl;
    cout << "愛好: ";
    for(int i = 0; i < new_person.hobbies_size(); ++i) {
        cout << new_person.hobbies(i) << " ";
    }
    cout << endl;
    
    return 0;
}

// 編譯命令:g++ -o test test.cpp person.pb.cc -lprotobuf -pthread

運行結果:

序列化完成,數據大小: 31 字節
反序列化結果:
姓名: 王五
年齡: 28
城市: 深圳
愛好: 編程 健身 美食

3. ProtoBuf的優缺點

優點:

  • 體積超小,壓縮效果好
  • 序列化/反序列化速度飛快
  • 跨語言支持好
  • 有版本兼容性(向前向后兼容)
  • 自動生成代碼,減少出錯

缺點:

  • 人類不可讀,調試困難
  • 需要預先定義schema
  • 學習成本相對較高
  • 不支持動態結構

四、性能大PK:數據說話

好了,說了這么多,到底誰更強?咱們用實際數據說話!

我做了個簡單的測試,用相同的數據結構,分別用 JSON 和 ProtoBuf 進行 1 萬次序列化和反序列化操作:

#include <chrono>
#include <iostream>
#include <nlohmann/json.hpp>
#include "person.pb.h"

using namespace std;
using namespace std::chrono;

struct TestResult {
    int serialize_time_ms;
    int deserialize_time_ms;
    size_t single_size;
    size_t total_size;
};

TestResult test_json() {
    const int iterations = 10000;
    TestResult result = {};
    
    // 測試數據
    nlohmann::json test_data = {
        {"name", "測試用戶名字比較長一些"},
        {"age", 25},
        {"city", "這是一個比較長的城市名稱"},
        {"hobbies", {"愛好1描述比較長", "愛好2描述比較長", "愛好3描述比較長"}}
    };
    
    // 序列化測試
    auto start = high_resolution_clock::now();
    vector<string> results;
    for(int i = 0; i < iterations; ++i) {
        results.push_back(test_data.dump());
    }
    auto end = high_resolution_clock::now();
    result.serialize_time_ms = duration_cast<milliseconds>(end - start).count();
    
    // 計算大小
    result.single_size = results[0].size();
    for(const auto& r : results) result.total_size += r.size();
    
    // 反序列化測試
    start = high_resolution_clock::now();
    for(const auto& data : results) {
        auto j = nlohmann::json::parse(data);
        // 模擬使用數據
        string name = j["name"];
    }
    end = high_resolution_clock::now();
    result.deserialize_time_ms = duration_cast<milliseconds>(end - start).count();
    
    return result;
}

TestResult test_protobuf() {
    const int iterations = 10000;
    TestResult result = {};
    
    // 序列化測試
    auto start = high_resolution_clock::now();
    vector<string> results;
    for(int i = 0; i < iterations; ++i) {
        Person person;
        person.set_name("測試用戶名字比較長一些");
        person.set_age(25);
        person.set_city("這是一個比較長的城市名稱");
        person.add_hobbies("愛好1描述比較長");
        person.add_hobbies("愛好2描述比較長");
        person.add_hobbies("愛好3描述比較長");
        
        string serialized;
        person.SerializeToString(&serialized);
        results.push_back(serialized);
    }
    auto end = high_resolution_clock::now();
    result.serialize_time_ms = duration_cast<milliseconds>(end - start).count();
    
    // 計算大小
    result.single_size = results[0].size();
    for(const auto& r : results) result.total_size += r.size();
    
    // 反序列化測試
    start = high_resolution_clock::now();
    for(const auto& data : results) {
        Person person;
        person.ParseFromString(data);
        // 模擬使用數據
        string name = person.name();
    }
    end = high_resolution_clock::now();
    result.deserialize_time_ms = duration_cast<milliseconds>(end - start).count();
    
    return result;
}

int main() {
    cout << "=== JSON vs ProtoBuf 性能大PK ===" << endl << endl;
    
    auto json_result = test_json();
    auto pb_result = test_protobuf();
    
    // 直觀對比輸出
    cout << "測試結果對比 (10000次操作)" << endl;
    cout << "┌──────────────┬─────────────┬─────────────┬──────────────┐" << endl;
    cout << "│    指標      │    JSON     │  ProtoBuf   │   ProtoBuf優勢 │" << endl;
    cout << "├──────────────┼─────────────┼─────────────┼──────────────┤" << endl;
    
    printf("│ 序列化耗時   │ %8dms │ %8dms │   快 %.1fx倍   │\n", 
           json_result.serialize_time_ms, pb_result.serialize_time_ms,
           (float)json_result.serialize_time_ms / pb_result.serialize_time_ms);
    
    printf("│ 反序列化耗時 │ %8dms │ %8dms │   快 %.1fx倍   │\n",
           json_result.deserialize_time_ms, pb_result.deserialize_time_ms,
           (float)json_result.deserialize_time_ms / pb_result.deserialize_time_ms);
    
    printf("│ 單個對象大小 │ %8zu字節│ %8zu字節│ 小 %4.1f%%    │\n",
           json_result.single_size, pb_result.single_size,
           (float)(json_result.single_size - pb_result.single_size) * 100 / json_result.single_size);
    
    printf("│ 總數據大小   │ %7.1fMB │ %7.1fMB │ 小 %4.1f%%    │\n",
           json_result.total_size / 1024.0 / 1024.0,
           pb_result.total_size / 1024.0 / 1024.0,
           (float)(json_result.total_size - pb_result.total_size) * 100 / json_result.total_size);
    
    cout << "└──────────────┴─────────────┴─────────────┴──────────────┘" << endl;
    
    cout << "\n結論:ProtoBuf在所有指標上都完勝JSON!" << endl;
    cout << "如果傳輸10000個對象,ProtoBuf能節省 "
         << (json_result.total_size - pb_result.total_size) / 1024.0 / 1024.0
         << "MB 流量" << endl;
    
    return 0;
}

測試結果(在我的虛擬機上跑的):

g++ -o test test.cpp person.pb.cc -lprotobuf -pthread

=== JSON vs ProtoBuf 性能大PK ===

測試結果對比 (10000次操作)
┌──────────────┬─────────────┬─────────────┬──────────────┐
│    指標      │    JSON     │  ProtoBuf   │   ProtoBuf優勢 │
├──────────────┼─────────────┼─────────────┼──────────────┤
│ 序列化耗時   │       22ms │        6ms │   快 3.7x倍   │
│ 反序列化耗時 │      135ms │        5ms │   快 27.0x倍   │
│ 單個對象大小 │      186字節│      147字節│ 小 21.0%    │
│ 總數據大小   │     1.8MB │     1.4MB │ 小 21.0%    │
└──────────────┴─────────────┴─────────────┴──────────────┘

結論:ProtoBuf在所有指標上都完勝JSON!
如果傳輸10000個對象,ProtoBuf能節省 0.371933MB 流量

?? 注意: 測試結果跟數據大小和數量有關,數據越大、數量越多,ProtoBuf優勢越明顯。建議用自己項目的真實數據測試一下!

五、實際應用場景:該選誰?

選JSON的情況:

  • Web開發:前后端通信的標配
  • 配置文件:需要人工編輯的配置
  • API接口:特別是REST API
  • 調試頻繁:需要經常查看數據內容
  • 快速原型:開發初期,快速驗證想法

選ProtoBuf的情況:

  • 高性能要求:游戲、實時系統
  • 網絡帶寬有限:移動端應用
  • 大數據傳輸:微服務間通信
  • 短期/臨時存儲:緩存、消息隊列
  • 跨語言通信:不同語言的服務間通信

六、小結:選擇建議

最后,給你一個選擇建議:

如果你是新手,建議先學JSON:

  • 上手簡單,出錯率低
  • 調試方便,看得見摸得著
  • 資料多,遇到問題容易解決

如果你追求性能,上ProtoBuf:

  • 速度快,體積小
  • 適合生產環境的高并發場景
  • 跨語言支持好

最理想的情況:兩個都會!

  • 不同項目用不同工具,根據需求選擇
  • 團隊內部可以靈活應對各種技術需求
  • 面試和技術交流時更有底氣

寫在最后

序列化這個話題,說簡單也簡單,說復雜也復雜。關鍵是要理解它的本質:就是為了讓數據能夠"旅行"。

就像你出門旅行要打包行李一樣,程序里的數據要"旅行"也需要打包。JSON就像是透明的行李箱,你能看到里面裝了什么;ProtoBuf就像是壓縮袋,體積小但看不見內容。

選擇哪個,取決于你的具體需求。不過記住一點:沒有銀彈,只有合適的工具。

希望這篇文章能幫你理清楚序列化這個概念。如果還有不明白的地方,歡迎在評論區留言,咱們一起討論!

記住:編程路上,我們都是學習者,一起加油! 

責任編輯:趙寧寧 來源: 跟著小康學編程
相關推薦

2009-08-24 17:14:08

C#序列化

2025-06-17 10:00:00

函數重載函數重寫C++

2009-08-06 11:16:25

C#序列化和反序列化

2009-08-25 14:24:36

C#序列化和反序列化

2024-01-30 13:32:51

JSON反序列化序列化

2021-11-18 07:39:41

Json 序列化Vue

2009-07-29 13:39:02

JSON序列化和反序列ASP.NET AJA

2021-01-19 06:05:28

Python數據分析編程語言

2009-08-25 14:43:26

C#序列化和反序列化

2015-05-08 12:41:36

C++序列化反序列化庫Kapok

2011-05-18 15:20:13

XML

2013-03-11 13:55:03

JavaJSON

2011-06-01 15:05:02

序列化反序列化

2024-10-07 08:26:53

2013-12-09 16:35:25

2011-06-01 14:50:48

2018-01-17 16:38:07

MSONJSON序列化

2019-11-20 10:07:23

web安全PHP序列化反序列化

2009-06-14 22:01:27

Java對象序列化反序列化

2022-08-06 08:41:18

序列化反序列化Hessian
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩欧美国产精品一区二区三区 | 皇色视频在线 | 欧美精品二区 | 91精品国模一区二区三区 | 精品国产一二三区 | 久久久99国产精品免费 | 精品亚洲视频在线 | 日韩免费1区二区电影 | 伊人网综合| 成年人在线观看视频 | 老司机午夜性大片 | 日韩国产一区二区 | 国产精品一区二区日韩 | 久久久高清 | 亚洲一区中文字幕 | 久久视频精品在线 | 国产一区二区三区久久 | 亚洲视频区 | 国产午夜精品一区二区三区四区 | 久久久一区二区三区 | 国产小网站 | 男女啪啪高潮无遮挡免费动态 | 欧美激情精品久久久久久变态 | 久久精品成人 | 中文字幕在线视频一区二区三区 | 亚州春色 | 国产资源视频 | 久久九九99 | www.久草.com | 亚洲高清视频一区二区 | 亚洲高清视频一区二区 | 国产视频精品视频 | 欧美日韩亚洲一区 | 国产精品美女久久久久久免费 | 欧美精品国产精品 | 久久久久久国产 | av日韩高清 | 免费激情 | 国产高清精品一区二区三区 | 亚洲综合婷婷 | 久久精品二区亚洲w码 |