【Protobuf】xml、json与protobuf有什么区别,protobuf详解(保姆篇)

在这里插入图片描述


更多相关内容可查看


简介

Protocol Buffers(简称 Protobuf)是 Google 开发的一种语言中立、平台中立、可扩展的序列化结构数据的机制。它主要用于将数据结构序列化为二进制格式,以便于高效传输和存储。Protobuf 在性能、文件大小和数据兼容性方面有着显著的优势。


Protobuf 的原理

Protobuf 的基本工作原理是:

  1. 定义数据结构:通过 .proto 文件定义数据结构。
  2. 生成代码:使用 Protobuf 编译器将 .proto 文件编译为目标编程语言的类或结构体。
  3. 序列化:将定义好的数据结构序列化为二进制格式。
  4. 反序列化:将二进制数据反序列化为原始数据结构。

Protobuf 使用一种紧凑的二进制格式来表示数据,相较于 XML 和 JSON,Protobuf 的数据体积更小,解析速度更快。


安装 Protobuf 编译器

对于 Linux 和 macOS 用户,你可以通过包管理器进行安装:

# Ubuntu
sudo apt-get install protobuf-compiler

# macOS
brew install protobuf

对于 Windows 用户,你可以从 Protobuf 的 GitHub 页面 下载预编译的二进制文件并将其添加到 PATH 中。


在 Python 中使用 Protobuf

安装语言特定的 Protobuf 库

需要安装 protobuf 包:

pip install protobuf

定义消息结构

Protobuf 使用 .proto 文件定义数据结构。一个 .proto 文件可以包含多个消息(message),每个消息定义了一种数据结构。以下是一个简单的 .proto 文件示例:

示例:person.proto

syntax = "proto3";

// Person 是一个消息类型
message Person {
    // 字段编号是必须的,字段类型包括 string、int32、bool 等
    int32 id = 1; // 通过编号区分字段
    string name = 2;
    string email = 3;
}

// AddressBook 包含一个 Person 的列表
message AddressBook {
    repeated Person people = 1; // repeated 表示一个列表
}

注释:

  • syntax = "proto3";:指定使用 Protobuf 版本 3。Protobuf 3 是当前推荐的版本,简化了语法并提供了许多新的功能。
  • message:定义一个消息类型。在这里,PersonAddressBook 是消息类型。
  • int32string:字段类型。
  • = 1= 2:字段编号。Protobuf 使用这些编号在二进制格式中标识字段。
  • repeated:表示一个字段可以包含多个值,这里表示 people 是一个 Person 对象的列表。

生成代码

使用 protoc 编译器将 .proto 文件编译为目标语言的代码

protoc --python_out=. person.proto

该命令将生成 person_pb2.py 文件,其中包含了 Protobuf 定义的类和方法。--python_out 参数指定输出目录。

使用 Protobuf 进行序列化和反序列化

编写 Python 代码

import person_pb2  # 由 protoc 生成的 Python 文件

# 创建一个 Person 对象
person = person_pb2.Person()
person.id = 123
person.name = "Alice"
person.email = "alice@example.com"

# 序列化
data = person.SerializeToString()

print("Serialized data:", data)

# 反序列化
new_person = person_pb2.Person()
new_person.ParseFromString(data)

print("Deserialized person:")
print("ID:", new_person.id)
print("Name:", new_person.name)
print("Email:", new_person.email)

注释:

  • SerializeToString():将 Person 对象序列化为二进制格式。
  • ParseFromString(data):将二进制数据反序列化为 Person 对象。

运行

python your_script.py

在 Java 中使用 Protobuf

安装和配置

安装Protobuf 编译器 protoc 和 Java 的 Protobuf 库。可以从 Protobuf 官方网站 下载编译器,并通过 Maven 来管理 Java 的 Protobuf 依赖。

pom.xml 中添加 Protobuf 依赖:

<dependencies>
  <dependency>
    <groupId>com.google.protobuf</groupId>
    <artifactId>protobuf-java</artifactId>
    <version>3.21.12</version> <!-- 确保使用最新版本 -->
  </dependency>
</dependencies>

编译 .proto 文件

使用 protoc 工具将 .proto 文件编译为 Java 类。假设你的 .proto 文件名为 person.proto,可以使用如下命令:

protoc --java_out=src/main/java person.proto

这条命令会在 src/main/java 目录下生成 Java 源文件。这些源文件包含了序列化和反序列化所需的代码。

使用生成的 Java 类

编译后,你会得到一个 Java 类,例如 PersonProtos.Person

创建和序列化对象
import com.google.protobuf.InvalidProtocolBufferException;
import com.example.PersonProtos.Person; // 假设生成的类在 com.example 包下

public class ProtobufExample {

  public static void main(String[] args) {
    // 创建 Person 对象
    Person person = Person.newBuilder()
        .setId(1)
        .setName("Alice")
        .setEmail("alice@example.com")
        .addPhones("123-456-7890")
        .addPhones("098-765-4321")
        .build();

    // 序列化对象为字节数组
    byte[] data = person.toByteArray();

    // 反序列化字节数组为 Person 对象
    try {
      Person deserializedPerson = Person.parseFrom(data);
      System.out.println("ID: " + deserializedPerson.getId());
      System.out.println("Name: " + deserializedPerson.getName());
      System.out.println("Email: " + deserializedPerson.getEmail());
      System.out.println("Phones: " + deserializedPerson.getPhonesList());
    } catch (InvalidProtocolBufferException e) {
      e.printStackTrace();
    }
  }
}

代码注释

  • Person.newBuilder():创建一个新的 Person 构建器,用于设置字段值。
  • setId(1):设置 id 字段为 1
  • setName(“Alice”):设置 name 字段为 "Alice"
  • setEmail(“alice@example.com”):设置 email 字段为 "alice@example.com"
  • addPhones(“123-456-7890”):向 phones 列表添加一个电话号码。
  • build():构建 Person 对象。
  • toByteArray():将 Person 对象序列化为字节数组。
  • parseFrom(data):从字节数组中反序列化 Person 对象。

高级特性

Protobuf 还支持一些高级特性,比如嵌套消息、枚举类型和自定义选项等。

嵌套消息示例

message AddressBook {
  message Person {
    int32 id = 1;
    string name = 2;
  }
  repeated Person people = 1; // AddressBook 包含多个 Person
}

枚举示例

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

message Person {
  int32 id = 1;
  string name = 2;
  PhoneType phone_type = 3;
}

性能优化和最佳实践

性能优化

  • 使用 repeated 字段:当需要存储多个值时,使用 repeated 字段而不是嵌套消息,以减少不必要的嵌套层级。
  • 选择合适的数据类型:根据实际需要选择合适的数据类型。例如,对于大范围的整数,使用 int64 可能更合适。

最佳实践

  • 字段编号管理:确保在消息定义中字段编号唯一,并避免修改现有字段编号,以保持向后兼容性。
  • 文档和注释:在 .proto 文件中添加注释,帮助团队成员理解数据结构和字段含义。
  • 测试和验证:使用 Protobuf 提供的工具和测试框架进行验证,确保序列化和反序列化的准确性。

xml、json与protobuf的区别

在项目中选择使用 XML、JSON 还是 Protobuf 作为数据格式,通常取决于具体的需求。

XML(可扩展标记语言)

优点:

  • 自描述性强:XML 标签和属性使得数据的结构和语义更加清晰,便于人类阅读和理解。
  • 成熟的标准:XML 是一种成熟的标准,有大量的工具和库支持,包括用于验证和转换的 XSD(XML Schema Definition)。
  • 广泛的支持:许多旧系统和协议仍然使用 XML,特别是在企业应用中。

缺点:

  • 冗长:XML 通常比 JSON 和 Protobuf 更冗长,文件体积较大。
  • 处理复杂度:解析和处理 XML 可能会比较复杂,尤其是涉及到复杂的 XML Schema 时。

JSON(JavaScript 对象表示法)

优点:

  • 简洁:JSON 格式比 XML 更简洁,容易生成和解析。
  • 易于处理:与 JavaScript 兼容,使得在 Web 应用中非常流行。大多数编程语言都有原生或第三方库支持 JSON。
  • 可读性强:JSON 数据结构简单明了,易于人类阅读和理解。

缺点:

  • 不支持复杂的数据类型:JSON 对于某些复杂的数据结构(例如自定义类型)支持不如 XML 和 Protobuf。
  • 没有类型约束:JSON 是无类型的,不支持数据验证机制。

Protobuf(协议缓冲)

优点:

  • 高效:Protobuf 在序列化和反序列化方面非常高效,生成的二进制数据比 XML 和 JSON 更小,速度更快。
  • 强类型:Protobuf 使用定义良好的消息结构,并支持类型检查,减少了数据格式错误的可能性。
  • 版本管理:Protobuf 支持向前和向后兼容性,方便在版本升级时管理数据格式的变化。

缺点:

  • 人类可读性差:Protobuf 使用二进制格式,直接阅读和调试不如 XML 和 JSON 直观。
  • 复杂性:需要定义 .proto 文件和使用相应的编译器生成代码,增加了开发和维护的复杂度。
  • 工具和支持:虽然 Protobuf 已经被广泛接受,但某些老旧系统和工具可能不原生支持 Protobuf。

更倾向于使用 XML 或 JSON 而非 Protobuf的原因

  1. 可读性和调试:XML 和 JSON 都是文本格式,更易于人类阅读和调试。对于需要频繁手动检查数据的场景,XML 和 JSON 更加直观。

  2. 兼容性和支持:许多旧系统和企业应用依赖于 XML 或 JSON,并且已有大量的库和工具支持这些格式。在这种情况下,迁移到 Protobuf 可能会带来额外的复杂性和兼容性问题。

  3. 简单性和开发速度:JSON 特别适合 Web 开发,因为它可以很容易地与 JavaScript 交互,并且解析速度较快。对于较简单的数据交换,JSON 可能足够用且易于实现。

  4. 开发团队的熟悉度:如果开发团队对 XML 或 JSON 更加熟悉,使用这些格式可以减少学习成本和开发难度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

来一杯龙舌兰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值