- 内存中的字典、列表、集合和各种对象,如何保存到一个文件当中?
- 如果是自己定义的类的实例,如何保存到一个文件当中?
- 如何从文件中读取数据,并让他们在内存中再次恢复成自己对应的类的实例?
- 例如将97存到文件中,你知道这是str(97)还是int(97)?
基于以上需求,我们要设计一套协议,按照某种规则,把内存的数据保存到文件中。文件是一个字节序列,使用必须把数据转换成字节序列,输出到文件。这就是序列化。
反之,从文件的字节序列恢复到内存并且还是原来的类型,这就是反序列化
将内存中对象存储下来,把它变成一个个字节,一般就是2进制
将文件中的一个个字节恢复成内存中的对象,二进制格式转为其他格式
- 序列化保存到文件之后才是持久化
- 可以将数据序列化后持久化,不一定是文件形式,也可也网络传输;也可以将文件中或者网络接收到的字节序列反序列化
import pickle
a = 99
b = 'c'
c = [48, 'abc']
d = {"a": "ddd", "b": 1}
with open('D:/Gitee/python/test/ser', 'wb+') as f:
pickle.dump(a, f)
用notepad++的hex插件打开看下
80 03 4b 63 2e
其中 63 这一位应该是真正的99
其他的都是描述99这个数字的东西
为了验证下我们的猜测,再看下s数字97,是不是显示61
80 03 4b 61 2e
看样子确实是我们想的样子
再来看下60000表示什么
80 03 4d 60 ea
在ipython里看看60000是什么
>>> hex(60000)
'0xea60'
>>>
ea60,看来写的文件是小端模式
import pickle
a = 99
b = 'c'
c = [48, 'abc']
d = {"a": "ddd", "b": 1}
with open('D:/Gitee/python/test/ser', 'wb+') as f:
pickle.dump(a, f)
pickle.dump(b, f)
pickle.dump(c, f)
pickle.dump(d, f)
notepad++ hex模式查看下
80 03 4b 63 2e 80 03 58 01 20 20 20 63 71 20 2e # ASCII: 数字99 对应16进制为63 字符'c' 对应的16进制为63
80 03 5d 71 20 28 4b 30 58 03 20 20 20 61 62 63 # ASCII: 数字48对应的16进制为30 'abc'对应的16进制显示为616263
71 01 65 2e 80 03 7d 71 20 28 58 01 20 20 20 61 # ASCII: 字符a 的16进制表示为61
71 01 58 03 20 20 20 64 64 64 71 02 58 01 20 20 # ASCII: 字符ddd的16进制表示为646464
20 62 71 03 4b 01 75 2e # ASCII: 字符b表示为62 数字1对应的16进制就是01
-
字符串存入时,需要反查ASCII表,然后将ASCII对应的索引写入文件中
- '0' -- \0x30
- '1' -- \0x31
- 'a' -- \0x61
-
数字存入时,直接将数值对应的16进制或2进制写入文件,也要注意大小端模式
- 1 -- \0x01
- 0 -- \0x00
- 99 -- \0x63
-
可以看到,写入字符串c和数字99,都是写入63(16进制),如果没有序列化,怎么区分?
-
不只是写入磁盘,在内存中,也是如此排序的
import pickle
a = '99'
aa = 99
b = 'c'
c = [48, 'abc']
d = {"a": "ddd", "b": 1}
with open('D:/Gitee/python/test/ser', 'wb+') as f:
pickle.dump(a, f)
pickle.dump(aa, f)
pickle.dump(b, f)
pickle.dump(c, f)
pickle.dump(d, f)
with open('D:/Gitee/python/test/ser', 'rb+') as f1:
for i in range(5):
x = pickle.load(f1)
print(type(x), x)
# 结果如下
<class 'str'> 99
<class 'int'> 99
<class 'str'> c
<class 'list'> [48, 'abc']
<class 'dict'> {'a': 'ddd', 'b': 1}
-
pickle模块只能在Python中使用,python中几乎所有的数据类型(列表,字典,集合,类等)都可以用pickle来序列化
-
pickle.dump(obj, file[, protocol])
- 序列化对象,并将结果数据流写入到文件对象中。
- 参数protocol是序列化模式,默认值为0,表示以文本的形式序列化
- protocol的值还可以是1或2,表示以二进制的形式序列化。
- 序列化对象,并将结果数据流写入到文件对象中。
-
pickle.load(file)
- 反序列化对象。将文件中的数据解析为一个Python对象
-
pickle.dumps()
- 将对象序列化为str,而不是保存到文件种
-
pickle.loads()
- 从str中读取字段,并反序列化
一般来说,本地序列化的情况,应用较少,大多数场景下都应用在网络传输中
将数据序列化后通过网络传输到远程节点,远程服务器上的服务将接收到的数据反序列化后,就可以使用了
但是,要注意一点,远程接收端,反序列化时必须有对应的数据类型,否则就会报错,尤其是自定义类,必须远程得有一致的定义
现在,大多数项目,都不是单机的,也不是单服务的,需要多个程序之间配合。需要通过网络将数据传送到其他节点上去,这就需要大量的序列化、反序列化的过程
但是,问题是,python与python之间还可以使用pickle解决序列化和反序列化,如果是跨平台、跨语言、跨协议的,pickle都不太合适,就需要公用的协议,如xml、json、protocol Buffer等
不同的协议,效率不同、学习曲线不同,适用于不同的场景,需要不同的情况去分析
json(JavaScript Object Notation ,JS对象标记)
json是一种轻量级的数据交换格式,它基于ECMAScript(W3c组织制定的JS规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据
Json 模块提供了四个方法: dumps、dump、loads、load
import json
a = {'a': [1, 2], 'b':{'c': 'd'}}
x = json.dumps(a)
print(type(a),'>>', type(x), a)
# 结果如下
<class 'dict'> >> <class 'str'> {'a': [1, 2], 'b': {'c': 'd'}}
把json得到的字符串放入js能直接解析
x = {'a': [1, 2], 'b': {'c': 'd'}}
{a: Array(2), b: {…}}
x.a
(2) [1, 2]
x.b
{c: "d"}
显而易见的,x.a这种调用方法明显是对象的操作
import json
a = {'a': [1, 2], 'b':{'c': 'd'}}
x = json.dumps(a)
print(type(a),'>>', type(x), a)
d1 = json.loads(x)
print(type(d1), d1)
# 结果如下
<class 'dict'> >> <class 'str'> {'a': [1, 2], 'b': {'c': 'd'}}
<class 'dict'> {'a': [1, 2], 'b': {'c': 'd'}}
import json
import pickle
a = {'a': [1, 2], 'b':{'c': 'd'}}
jsona = json.dumps(a)
picka = pickle.dumps(a)
print("json's length{}\npickle's length{}".format(len(jsona), len(picka)))
# 结果如下
json's length30
pickle's length53
python支持少量的内建数据类型到json类的转换
python类型 | json类型 |
---|---|
True | true |
False | false |
None | null |
str | string |
int | integer |
float | float |
list | array |
dict | object |
python类型 | json类型 |
---|---|
dumps | json编码 |
dump | json编码存入文件 |
loads | json解码 |
load | json解码存入文件 |
- 一般json的编码的数据很少落地,数据都是通过网络传输,传输的时候,要考虑压缩它
- 本质上来说它就是个文本,就是个字符串
- json很简单,几乎所有的编程语言都支持json,所以应用范围十分广泛
MessagePack是一种有效的二进制序列化格式。 它使您可以在JSON之类的多种语言之间交换数据。 但是它更快,更小。 该软件包提供用于读取和写入MessagePack数据的CPython绑定。
MessagePack对字符串的压缩效率大概是json的一半,一般用于python标准库的内部数据传输
pip install msgpack
import json
import pickle
import msgpack
a = {'a': [1, 2], 'b':{'c': 'd'}}
jsona = json.dumps(a)
picka = pickle.dumps(a)
msga = msgpack.dumps(a)
print("json's length{}\npickle's length{}\nmsg's length{}".format(len(jsona), len(picka), len(msga)))
# 结果如下
json's length30
pickle's length53
msg's length13