美文网首页
pickle--序列化保存数据

pickle--序列化保存数据

作者: 马尔代夫Maldives | 来源:发表于2023-02-11 14:09 被阅读0次

说明:

  • 有时候需要将list、dictionary、string、自己定义的数据对象保存在磁盘中。常规的file.write()方法,无论写入什么类型的内容,file.read()出来的结果都是字符串(string)。 我们更希望写入前是什么类型,读出后也是什么类型。pickle模块就能干这件事!
  • pickle模型的核心功能是将对象序列化成一个Python 语言专用的二进制格式,同时也能反序列化回原来的对象,因此,该模块又叫序列化模块pickle既可以将对象序列化在程序中,也可以序列化到文件中(即保存在文件中,正是我们想要的。)
  • 注意:pickle后的结果是不可认读的(打开乱码),并只能用于Python环境,不能用作与其它语言进行数据交换
import pickle

一. 将对象序列化到文件,再从文件反序列化成对象

用到的两个方法:
pickle.dump(obj, file, [,protocol]):
将数据“对象obj”,保存到“文件file”中,使用有3种协议,0为ASCII(默认),1为旧式二进制,2为新式二进制协议(更高效一些)。
pickle.load(file):
读取已经存在的序列化文件file中的内容,并将其反序列回obj对象。

下例中list a,用pickle.dumple()序列化进文件,再用pickle.load()反序列化,结果依然是list(包括内部元素的类型也没变)。而如果用普通的file.write()写入文件,无论写入的内容是什么类型,用file.read()打开返回的都是字符串类型'str',这对于后续处理是极为不利的。

a = ['A',100,['cat']]
with open('text.txt', 'wb') as file1:
    pickle.dump(a, file1)  # 将a写入文件
    
with open('text.txt', 'rb') as file2:    
    b = pickle.load(file2)  # 直接从file2中获取数据
    print(b,':' ,type(b))
    print(b[0],':', type(b[0]))
    print(b[1],':', type(b[1]))
    print(b[2],':', type(b[2]))

输出:
['A', 100, ['cat']] : <class 'list'>
A : <class 'str'>
100 : <class 'int'>
['cat'] : <class 'list'>

注意:虽然上例中生成的文件是“text.txt”,但实际上是无法直接打开的二进制文件。

text.txt.png

1.1 多个对象写入文件(序列化)和读取文件(反序列化)问题

pickle在使用过程由于其特殊的内容标记,使得文件dump()几次,就必须load()几次才能将数据全部读出来:

a=1
b=[2]
c={'name':'Lili'}

with open("text.txt","wb") as f:
    pickle.dump(a,f)
    pickle.dump(b,f)
    pickle.dump(c,f)

with open("text.txt","rb") as f :
    print(pickle.load(f)) # 输出q
    # print(pickle.load(f)) # 输出b
    # print(pickle.load(f)) # 输出c

输出:
1

实际中不可能记住所有的dump()次数,也就无法准确的使用load()多次的方式来取出值。
可以直接无限循环执行pickle.load(),直至其报错才停止:

# 接上面程序
with open("text.txt","rb") as f :
    while True:
        try:
            print(pickle.load(f))
        except:
            break

输出:
1
[2]
{'name': 'Lili'}

1.2 反序列化时,对应类型的定义必须已经存在,否则出错

如下例,自定义了一个类Person,并生成了一个对象person1,利用pickle.dump()将其序列化进text.txt文件,然后利用pickle.load()将其反序列化,结果没问题。但是如果启用“del Person”这句代码将类的定义删除,则运行结果出错,因为在反序列化时无法为person1找到对应的类别定义。

# 定义一个类
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def show(self):
        print(self.name+":"+str(self.age))

# 生成一个具体对象
person1= Person("Lili", 6)
person1.show()

# 利用pickle.dump()将对象person序列化到文件text.txt
with open('text.txt', 'wb') as f:
    pickle.dump(person1, f, 0)

# del Person  # 删除定义

# 利用pickle.load()从text.txt中反序列化对象person
with open('text.txt', 'rb') as f:
    is_person = pickle.load(f)
    is_person.show()

输出:
Lili:6
Lili:6

二. 将对象序列化,再反序列化成对象,但不写入文件

用到的两个方法:
pickle.dumps(obj, [, protocol]):
将obj对象序列化为string形式,而不存入文件,protocol默认为0。若为负值或HIGHEST_PROTOCOL,则使用最高的协议版本。
pickle.loads(string):
将前述序列化的string反序列化成obj。**

a = ['A',100,['cat']]
print('原始对象a:', a,';',type(a))

a_seqs = pickle.dumps(a) # 将a序列化(即转化成二进制)
print('a序列化结果:', a_seqs,';',type(a_seqs) )

a_back = pickle.loads(a_seqs)  # 将序列化结果反序列化成a
print('a反序列化结果:', a_back,';',type(a_back) )

输出:
原始对象a: ['A', 100, ['cat']] ; <class 'list'>
a序列化结果: b'\x80\x04\x95\x14\x00\x00\x00\x00\x00\x00\x00]\x94(\x8c\x01A\x94Kd]\x94\x8c\x03cat\x94ae.' ; <class 'bytes'>
a反序列化结果: ['A', 100, ['cat']] ; <class 'list'>

参考:
https://www.cnblogs.com/ranxf/p/7800179.html
https://zhuanlan.zhihu.com/p/419362785

相关文章

网友评论

      本文标题:pickle--序列化保存数据

      本文链接:https://www.haomeiwen.com/subject/swfhkdtx.html