• Google之ProtoBuf简单使用


    前言

    在学习Netty时,发现可以整合ProtoBuf相关的处理器,所以先来学习一下ProtoBuf相关知识。

    关于ProtoBuf

    ProtoBuf可以看做一个序列化(对象转成字节数组)和反序列化(字节数组转成对象)工具。相比Java本身的序列化,ProtoBuf可以支持跨语言,如使用Java序列化,使用Python来反序列化。相比XML这个文件格式,ProtoBuf序列化生成的数据更小,传输效率更高。

    下载编译器

    github地址,这里我们下载windows版本的编译器protoc-3.20.0-win64.zip,解压即可用。

    定义proto文件

    syntax = "proto3";
    
    package tutorial;
    
    option java_package = "com.imooc.sourcecode.java.google.protobuf.test1";
    option java_outer_classname = "PersonProto";
    
    message Person {
        optional string name = 1;
        optional int32 email = 2;
        enum PhoneType {
            MOBILE = 0;
            HOME = 1;
        }
        message PhoneNumber {
            optional string number = 1;
            optional PhoneType type = 2;
        }
        repeated PhoneNumber phones = 4;
    }
    

    syntax = "proto3" 表示使用proto3版本,默认使用proto2版本。
    optional 表示当前字段可选,非必填。
    string name = 1 每个字段需要有一个唯一的号码,必须大于0。
    enum 表示枚举类型。
    repeated 表示可重复,Java中就是List。
    message 可以看做一个Java类,可以嵌套。

    Java处理

    添加maven依赖

    <dependency>
      <groupId>com.google.protobuf</groupId>
      <artifactId>protobuf-java</artifactId>
      <version>3.19.4</version>
    </dependency>
    <dependency>
      <groupId>com.google.protobuf</groupId>
      <artifactId>protobuf-java-util</artifactId>
      <version>3.19.4</version>
      <scope>runtime</scope>
    </dependency>
    

    根据proto文件创建Java序列化和反序列化代码

    protoc -I=$SRC_DIR --java_out=$DST_DIR person.proto
    

    -I表示proto文件的路径,--java_out表示生成代码的路径,实际命令为

    .\protoc.exe -I=D:\java\code_resp\github_resp\source_code\src\main\java\com\imooc\sourcecode\java\google\protobuf\test1 --java_out=D:\java\code_resp\github_resp\source_code\src\main\java person.proto
    

    --java_out值不要包含具体的包路径,proto文件中已经配置了。

    将对象序列化到文件中

    import com.imooc.sourcecode.java.google.protobuf.test1.PersonProto.Person;
    import com.imooc.sourcecode.java.google.protobuf.test1.PersonProto.Person.PhoneNumber;
    import com.imooc.sourcecode.java.google.protobuf.test1.PersonProto.Person.PhoneType;
    import java.io.FileOutputStream;
    import java.io.IOException;
    
    public class Client {
    
      public static void main(String[] args) throws IOException {
        PhoneNumber phoneNumber = PhoneNumber.newBuilder()
            .setNumber("2")
            .setType(PhoneType.HOME)
            .build();
        Person person = Person.newBuilder()
            .setName("lisi")
            .setEmail(12)
            .addPhones(phoneNumber)
            .build();
        person.writeTo(new FileOutputStream("D:/testjar/java_serialize_person"));
      }
    
    }
    

    使用Builder模式创建Person对象并序列化到文件中。

    将Python序列化的文件反序列化为对象

    import com.imooc.sourcecode.java.google.protobuf.test1.PersonProto.Person;
    import java.io.FileInputStream;
    import java.io.IOException;
    
    public class Client2 {
    
      public static void main(String[] args) throws IOException {
        Person person = Person.parseFrom(new FileInputStream("D:/testjar/python_serialize_person"));
        System.out.println(person);
      }
    
    }
    

    读取文件并反序列化为对象。

    Python处理

    安装依赖

    pip install protobuf
    

    PyCharm中可以这样安装

    根据proto文件创建Python序列化和反序列化代码

    protoc -I=$SRC_DIR --python_out=$DST_DIR person.proto
    

    -I表示proto文件的路径,--python_out表示生成代码的路径,实际命令为

    .\protoc.exe -I=D:\java\code_resp\PycharmProjects\test_protobuf\protobuf --python_out=D:\java\code_resp\PycharmProjects\test_protobuf\protobuf person.proto 
    

    将Java序列化的文件反序列化为对象

    import person_pb2
    
    
    def test_deserialize():
        with open("D:/testjar/java_serialize_person", "r") as rf:
            bytes_read = rf.read()
            person = person_pb2.Person()
            # 需要将字符串转成字节数组
            person.ParseFromString(bytes_read.encode())
            print(person)
        return
    
    
    if __name__ == "__main__":
        test_deserialize()
        pass
    

    从文件中读取到的是字符串类型,需要转成字节数组类型,核心为ParseFromString()方法。

    将对象序列化到文件中

    import person_pb2
    
    
    def test_serialize():
        person = person_pb2.Person()
        person.name = "zhangsan"
        person.email = 34
        phone = person.phones.add()
        phone.number = "3"
        phone.type = person.PhoneType.MOBILE
        with open("D:/testjar/python_serialize_person", "wb") as f:
            f.write(person.SerializeToString())
        return
    
    
    if __name__ == "__main__":
        test_serialize()
        pass
    
    

    创建一个Person对象并序列化到文件中,核心为SerializeToString()方法。

    总结

    通过上述测试,我们可以发现,Java序列化的文件通过Python是可以反序列化成功的,Python序列化的文件通过Java也是可以反序列化成功的。更多ProtoBuf相关用法,请查看官方文档

    参考

    Protocol Buffers
    protobuf(proto3)极简入门(python为例)
    深入 ProtoBuf - 简介

  • 相关阅读:
    从Pycharm说起
    前端工程师小A学习JS的旅程
    模板引擎开发(一)
    Bootstrap01
    Passbook详解与开发案例
    DLL文件知多少?
    C#中的索引器的简单理解和用法
    python 的列表遍历删除
    Node.js与Golang使用感受与小结1
    解决设计中的两难问题
  • 原文地址:https://www.cnblogs.com/strongmore/p/16124002.html
Copyright © 2020-2023  润新知