序列化之protobuf

 protobuf的编码及序列化介绍我觉得这两篇还可以

深入 ProtoBuf - 编码

深入 ProtoBuf - 序列化源码解析

一、简介

protobuf为Google开发的高性能序列化和反序列化工具

官方文档给出的定义和描述:

protocol buffers 是一种语言无关、平台无关、可扩展的序列化结构数据的方法,它可用于(数据)通信协议、数据存储等。

Protocol Buffers 是一种灵活,高效,自动化机制的结构数据序列化方法-可类比 XML,但是比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单。

你可以定义数据的结构,然后使用特殊生成的源代码轻松的在各种数据流中使用各种语言进行编写和读取结构数据。你甚至可以更新数据结构,而不破坏由旧数据结构编译的已部署程序。

特点:

语言无关、平台无关。即 ProtoBuf 支持 Java、C++、Python 等多种语言,支持多个平台

高效。即比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单。

扩展性、兼容性好。你可以更新数据结构,而不影响和破坏原有的旧程序

.protoc文件语法

 例子AddressBook.proto

syntax = "proto2";

package tutorial;

option java_package = "com.simonwang.java.learn.protobufentities";
option java_outer_classname = "AddressBookProtos";

message Person{
    required string name = 1;
    required int32 id = 2;
    optional string email = 3;

    enum PhoneType{
        MOBILE = 0;
        HOME = 1;
        WORK = 2;
    }

    message PhoneNumber{
        required string number = 1;
        optional PhoneType type = 2 [default = HOME];
    }

    repeated PhoneNumber phones = 4;
}

message AddressBook{
    repeated Person people = 1;
}

定义形式:

//类名
message xxx {
  字段规则 类型 名称 = 字段编号;
}

字段规则:

required -> 字段只能也必须出现 1 次

optional -> 字段可出现 0 次或1次

repeated -> 字段可出现任意多次(包括 0)用于集合

标量值类型

.proto TypeNotesC++ TypeJava TypePython Type[2]Go Type
double doubledoublefloat*float64
float floatfloatfloat*float32
int32使用可变长度编码。编码负数的效率低 - 如果你的字段可能有负值,请改用 sint32int32intint*int32
int64使用可变长度编码。编码负数的效率低 - 如果你的字段可能有负值,请改用 sint64int64longint/long[3]*int64
uint32使用可变长度编码uint32int[1]int/long[3]*uint32
uint64使用可变长度编码uint64long[1]int/long[3]*uint64
sint32使用可变长度编码。有符号的 int 值。这些比常规 int32 对负数能更有效地编码int32intint*int32
sint64使用可变长度编码。有符号的 int 值。这些比常规 int64 对负数能更有效地编码int64longint/long[3]*int64
fixed32总是四个字节。如果值通常大于 228,则比 uint32 更有效。uint32int[1]int/long[3]*uint32
fixed64总是八个字节。如果值通常大于 256,则比 uint64 更有效。uint64long[1]int/long[3]*uint64
sfixed32总是四个字节int32intint*int32
sfixed64总是八个字节int64longint/long[3]*int64
bool boolbooleanbool*bool
string字符串必须始终包含 UTF-8 编码或 7 位 ASCII 文本stringStringstr/unicode[4]*string
bytes可以包含任意字节序列stringByteStringstr[]byte

字段编号:

0 ~ 536870911(除去 19000 到 19999 之间的数字)

如果你在 .proto 文件中定义 RPC 服务,你应该使用驼峰命名法(首字母大写)命名 RPC 服务以及其中的 RPC 方法:

service FooService {
  rpc GetSomething(FooRequest) returns (FooResponse);
}

Maps定义及特性

如果要在数据定义中创建关联映射,protocol buffers 提供了一种方便快捷的语法:

map<key_type, value_type> map_field = N;

...其中 key_type 可以是任何整数或字符串类型(任何标量类型除浮点类型和 bytes)。请注意,枚举不是有效的 key_typevalue_type 可以是除 map 之外的任何类型。

因此,举个例子,如果要创建项目映射,其中每个 "Project" message 都与字符串键相关联,则可以像下面这样定义它:

map<string, Project> projects = 3;

生成的 map API 目前可用于所有 proto2 支持的语言。你可以在相关的 API 参考 中找到有关所选语言的 map API 的更多信息。

特性

  • maps 不支持扩展
  • maps 不能是 repeated、optional、required
  • map 值的格式排序和 map 迭代排序未定义,因此你不能依赖于特定顺序的 map 项
  • 生成 .proto 的文本格式时,maps 按键排序。数字键按数字排序
  • 当解析或合并时,如果有重复的 map 键,则使用最后看到的键。从文本格式解析 map 时,如果存在重复键,则解析可能会失败

向后兼容性

map 语法等效于以下内容,因此不支持 map 的 protocol buffers 实现仍可处理你的数据:

message MapFieldEntry {
  optional key_type key = 1;
  optional value_type value = 2;
}

repeated MapFieldEntry map_field = N;

任何支持 maps 的 protocol buffers 实现都必须生成和接受上述定义所能接受的数据。

导入定义:

如果要用作字段类型的 message 类型已在另一个 .proto 文件中定义,可以通过导入来使用其他 .proto 文件中的定义。

要导入另一个 .proto 的定义,可以在文件顶部添加一个 import 语句:

import "myproject/other_protos.proto";

Packages

你可以将 optional 可选的包说明符添加到 .proto 文件,以防止 protocol message 类型之间的名称冲突。

package foo.bar;
message Open { ... }

然后,你可以在定义 message 类型的字段时使用包说明符:

message Foo {
  ...
  required foo.bar.Open open = 1;
  ...
}

package 影响生成的代码的方式取决于你所选择的语言:

  • C++ 中,生成的类包含在 C++ 命名空间中。例如,Open 将位于命名空间 foo::bar 中。
  • Java 中,除非在 .proto 文件中明确提供选项 java_package,否则该包将用作 Java 包
  • Python 中,package 指令被忽略,因为 Python 模块是根据它们在文件系统中的位置进行组织的

请注意,即使 package 指令不直接影响生成的代码,但是例如在 Python 中,仍然强烈建议指定 .proto 文件的包,否则可能导致描述符中的命名冲突并使 proto 对于其他语言不方便。

Packages 和名称解析

protocol buffer 语言中的类型名称解析与 C++ 类似:首先搜索最里面的范围,然后搜索下一个范围,依此类推,每个包被认为是其父包的 “内部”。一个领先的 '.'(例如 .foo.bar.Baz)意味着从最外层的范围开始。

protocol buffer 编译器通过解析导入的 .proto 文件来解析所有类型名称。每种语言的代码生成器都知道如何使用相应的语言类型,即使它具有不同的范围和规则。

二、安装及使用

1.电脑上面安装protoc,命令行使用

下载地址 https://github.com/protocolbuffers/protobuf/releases

解压protoc-3.12.3-win64.zip,双击protoc.exe,将/bin路径配入环境变量

在命令行窗口中输入protoc查看是否配置正确

 准备AddressBook.proto文件,内容看上文

cmd中执行命令:

 protoc.exe --java_out=./outputFile ./AddressBook.proto

其中./outputFile是生成.java文件的目录,而./AddressBook.proto是指定根据哪个./proto文件来生成 

2.Idea中以maven的方式使用

这种方式可以本机电脑不安装protoc,是maven编辑的时候现去下载指定版本的protoc

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.sid</groupId>
    <artifactId>test-serialize</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>
        <!-- https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java -->
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java</artifactId>
            <version>3.12.2</version>
        </dependency>

    </dependencies>

    <build>
        <defaultGoal>package</defaultGoal>
        <extensions>
            <extension>
                <groupId>kr.motd.maven</groupId>
                <artifactId>os-maven-plugin</artifactId>
                <version>1.5.0.Final</version>
            </extension>
        </extensions>
        <plugins>
            <plugin>
                <!--protobuf 插件默认的 Phase 为 GenerateCode-->
                <groupId>org.xolstice.maven.plugins</groupId>
                <artifactId>protobuf-maven-plugin</artifactId>
                <version>0.5.1</version>
                <configuration>
                    <protoSourceRoot>${project.basedir}/src/main/proto</protoSourceRoot>
                    <protocArtifact>com.google.protobuf:protoc:3.12.2:exe:${os.detected.classifier}</protocArtifact>
                    <outputDirectory>${project.build.directory}/generated-sources/protobuf/java</outputDirectory>
                </configuration>
                <executions>
                    <execution>
                        <!--把 Compile mojo和 test compile mojo 绑定到 GenerateCode 阶段。
                        这样,在 GenerateCode 阶段,会执行此插件的两个 mojo。否则,在Maven 默认的 Compile 或 Test 阶段
                        ,不会执行编译动作。-->
                        <goals>
                            <goal>compile</goal>
                            <goal>test-compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

目录

注意需要把src/main/proto,右击 proto 目录,在『Mark Directory as...』下选择『Sources Root』

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值