# 关于二进制
# pickle
:Python 的标准库,用于将 Python 对象序列化成二进制格式。
- 官方文档 (opens new window)
- 它序列化后的数据不是 XML、JSON 等通用格式,只能被 Python 解析读取。
# 例
- 序列化:
>>> import pickle >>> pickle.dumps('Hello') # 序列化一个字符串 b'\x80\x04\x95\t\x00\x00\x00\x00\x00\x00\x00\x8c\x05Hello\x94.' >>> with open('f1', 'wb') as f: ... f.write(pickle.dumps('Hello')) # 将序列化的数据保存到文件中 ... 24
>>> class Test: ... a = 1 ... >>> Test() <__main__.Test object at 0x0000018564081490> >>> pickle.dumps(_) # 序列化自定义类型的对象 b'\x80\x04\x95\x18\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main__\x94\x8c\x04Test\x94\x93\x94)\x81\x94.'
- 反序列化:
>>> with open('f1', 'rb') as f: ... data = f.read() ... >>> pickle.loads(data) 'Hello'
# ProtoBuf
:Protocol Buffer ,一种序列化数据的格式,属于二进制格式。
- 官方文档 (opens new window)
- 2008 年,由 Google 公司发布。
- 与 JSON 相比, ProtoBuf 格式不能供人阅读,但被机器解析的速度更快、存储体积更小,提高了在不同程序之间传递数据的效率。
- 与 pickle 相比, ProtoBuf 格式独立于语言、平台,是一种通用的二进制格式。
# 语法
- 用
//
声明单行注释,用/*
、*/
声明多行注释。 - 每条语句必须以分号 ; 结尾。
- 通常在扩展名为 .proto 的文本文件中定义 ProtoBuf 的消息模型(message)。
- message 中可以包含多个字段,支持 bool、int32、string 等多种数据类型。
- message 支持嵌套。
- message 中每个字段需要定义一个大于 1 的编号,不能重复,用于在二进制格式中定位。
- message 中每个字段需要在开头加上一种修饰符:
- optional :表示创建消息时,该字段是可选的,可以不赋值。此时采用系统的默认值,比如 int32 的默认值为 0 。
- required :表示该字段是必须赋值的。该修饰符在 proto2 不建议使用,在 proto3 不支持。
- repeated :表示该字段可以重复赋值,此时视为动态大小的数组。
- 语法版本主要有两个:
- proto2
- proto3
- optional 修饰符改名为 singular ,并默认采用。
- required 修饰符被弃用。
# 例
下载 protoc (opens new window) ,然后安装:
yum install -y gcc-g++ ./configure make install
- protoc 是用 C++ 开发的命令行工具,用于编译 .proto 文件,生成各种编程语言的源文件。
编写一个 .proto 文件,定义消息模型:
syntax = "proto3"; // 声明语法版本 package test; // 声明当前文件属于一个名为 test 的包 // import "test2.proto"; // 可通过 import 导入其它包 message Person{ string name = 1; int32 age = 2; message Email{ string address = 1; } repeated Email emails = 3; }
用 protoc 将 .proto 文件编译成 py 文件:
[root@CentOS ~]# protoc test.proto --python_out=. # 还可用 -I <PATH> 指定目录用于寻找 import 的包 [root@CentOS ~]# ls test_pb2.py test.proto
在 Python 解释器中调用:
>>> import test_pb2 >>> p = test_pb2.Person() >>> p.name = 'Leo' >>> p.age = 12 >>> p # 显示方便阅读的文本格式。 emails 字段此时取值为空,因此不显示 name: "Leo" age: 12 >>> p.SerializeToString() # 序列化成二进制格式 b'\n\x03Leo\x10\x0c' >>> p2 = test_pb2.Person() >>> p2.ParseFromString(p.SerializeToString()) # 反序列化,赋值给另一个消息
>>> p.name = 1 # 赋值错误的数据类型时会报错 TypeError: Cannot set test.Person.name to 1: 1 has type <class 'int'>, but expected one of: (<class 'bytes'>, <class 'str'>) >>> p.phone = '' # 赋值给未定义的字段时会报错 AttributeError: 'Person' object has no attribute 'phone'
>>> p.emails # repeated 类型字段保存为数组形式 [] >>> e = p.emails.add() # 添加一个元素,返回其引用 >>> e.address = '[email protected]' >>> p.emails [address: "[email protected]" ]
- 需要安装第三方库
pip install protobuf
。
- 需要安装第三方库