1. 程式人生 > 程式設計 >Protobuf 安裝及 Python、C# 使用示例

Protobuf 安裝及 Python、C# 使用示例

01| 簡介

Protobuf(Protocol Buffers),是 Google 開發的一種跨語言、跨平臺的可擴充套件機制,用於序列化結構化資料。

與 XML 和 JSON 格式相比,protobuf 更小、更快、更便捷。protobuf 目前支援 C++、Java、Python、Objective-C,如果使用 proto3,還支援 C#、Ruby、Go、PHP、JavaScript 等語言。

官網地址:developers.google.cn/protocol-bu…

GitHub 地址:github.com/protocolbuf…

優點:

  • 效能好
  • 跨語言

缺點:

  • 二進位制格式可讀性差:為了提高效能,protobuf 採用了二進位制格式進行編碼,這直接導致了可讀性差。
  • 缺乏自描述:XML 是自描述的,而 protobuf 不是,不配合定義的結構體是看不出來什麼作用的。

02| 安裝

2.1 Windows 下安裝

下載地址:github.com/protocolbuf…

下載 protoc-3.9.1-win64.zip,這個是編譯後的壓縮包,相當於綠色版,解壓後,將其下的 bin 目錄新增到環境變數就可以了,省去了安裝的麻煩。

然後開啟命令提示符,輸入命令:

protoc --version
複製程式碼

成功顯示版本號,則表示安裝成功。如下圖:

protobuf 安裝(1).png

03| 簡單使用

3.1 編譯

使用 protobuf 首先需要定義 .proto 檔案,先來看一個簡單的例子。

定義 Person.proto 檔案,內容如下:

syntax = "proto3";
package Test;

message Person {
  string Name = 1;
  int32 Age = 2;
  bool Marriage = 3;
}
複製程式碼
  • syntax = "proto3"; 指定正在使用 proto3 語法,否則 protobuf 將預設使用的是 proto2。
  • package Test; 指定名稱空間(C# 中)。
  • message 是關鍵字,定義結構化資料。
  • 等號後面的數字是欄位唯一編號(注意不是欄位的值),用於二進位制格式訊息中標識欄位。

protoc 是 protobuf 自帶的編譯器,可以將 .proto 檔案編譯成 java、python、go、C# 等多種語言的程式碼,直接引用。

編譯命令:

protoc -I=E:\GL\Test2017 --python_out=E:\GL\Test2017 Person.proto
複製程式碼

編譯命令說明:

  • -I 表示原始檔(.proto 檔案)所在資料夾路徑。
  • --python_out 表示目標語言為 python,且指定生成的 .py 檔案存放目錄。相應的,C# 為 csharp_out,
  • Person.proto 為原始檔檔名,如果有多個,空格隔開。

3.2 Python 示例

安裝 protobuf

呼叫編譯命令編譯 Person.proto,編譯後生成檔案:Person_pb2.py,新增至專案中,序列化和反序列化示例如下:

import Person_pb2

person = Person_pb2.Person()
person.Name = '張三'
person.Age = 20
person.Marriage = True

# 序列化
b = person.SerializeToString()
print(b)

# 反序列化
p = Person_pb2.Person()
p.ParseFromString(b)
print(f'Name: {p.Name}; Age: {p.Age}; Marriage: {p.Marriage}')
複製程式碼

輸出:

b'\n\x06\xe5\xbc\xa0\xe4\xb8\x89\x10\x14\x18\x01'
Name: 張三; Age: 20; Marriage: True
複製程式碼

注意,不能這樣寫,這是錯誤的:

p = Person_pb2.Person().ParseFromString(b)
複製程式碼

3.3 C# 示例

C# 下的 Protobuf 有 3 個版本:

這裡我們介紹谷歌官方版本。

在 VS 中,通過 NuGet 安裝 'google.protobuf' 包。

using Google.Protobuf;
using System;
using Test;

namespace Protobuf
{
    class Program
    {
        static void Main(string[] args)
        {
            Person person = new Person();
            person.Name = "張三";
            person.Age = 20;
            person.Marriage = true;

            // 序列化
            byte[] buffer = person.ToByteArray();

            foreach (byte b in buffer)
            {
                Console.Write(b.ToString("X2") + " ");
            }
            Console.WriteLine();

            // 反序列化
            Person p = Person.Parser.ParseFrom(buffer);

            Console.WriteLine(string.Format("Name: {0},Age: {1},Marriage: {2}",p.Name,p.Age,p.Marriage));

            Console.Read();
        }
    }
}
複製程式碼

輸出:

0A 06 E5 BC A0 E4 B8 89 10 14 18 01
Name: 張三,Age: 20,Marriage: True
複製程式碼

比較一下 Python 的輸出,好像不一樣,Python 中第一個位元組是 \n,而這裡是 0A。\n 在 ASCII 中的值就是 0A。所以兩種語言的序列化結果是一樣的。