W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
在《文件(1)》和《文件(2)》中,已經(jīng)學(xué)習(xí)了如何讀寫文件。
如果在程序中,有數(shù)據(jù)要保存到磁盤中,放到某個(gè)文件中是一種不錯(cuò)的方法。但是,如果像以前那樣存,未免有點(diǎn)凌亂,并且沒(méi)有什么良好的存儲(chǔ)格式,導(dǎo)致數(shù)據(jù)以后被讀出來(lái)的時(shí)候遇到麻煩,特別是不能讓另外的使用者很好地理解。不要忘記了,編程是一個(gè)合作的活。還有,存儲(chǔ)的數(shù)據(jù)不一定都是類似字符串、整數(shù)那種基礎(chǔ)類型的。
總而言之,需要將要存儲(chǔ)的對(duì)象格式化(或者叫做序列化),才好存好取。這就有點(diǎn)類似集裝箱的作用。
所以,要用到本講中提供的方式。
pickle是標(biāo)準(zhǔn)庫(kù)中的一個(gè)模塊,還有跟它完全一樣的叫做cpickle,兩者的區(qū)別就是后者更快。所以,下面操作中,不管是用import pickle
,還是用import cpickle as pickle
,在功能上都是一樣的。
>>> import pickle
>>> integers = [1, 2, 3, 4, 5]
>>> f = open("22901.dat", "wb")
>>> pickle.dump(integers, f)
>>> f.close()
用pickle.dump(integers, f)
將數(shù)據(jù)integers保存到了文件22901.dat中。如果你要打開(kāi)這個(gè)文件,看里面的內(nèi)容,可能有點(diǎn)失望,但是,它對(duì)計(jì)算機(jī)是友好的。這個(gè)步驟,可以稱之為將對(duì)象序列化。用到的方法是:
pickle.dump(obj,file[,protocol])
下面換一種數(shù)據(jù)格式,并且做對(duì)比:
>>> import pickle
>>> d = {}
>>> integers = range(9999)
>>> d["i"] = integers #下面將這個(gè)dict格式的對(duì)象存入文件
>>> f = open("22902.dat", "wb")
>>> pickle.dump(d, f) #文件中以ascii格式保存數(shù)據(jù)
>>> f.close()
>>> f = open("22903.dat", "wb")
>>> pickle.dump(d, f, True) #文件中以二進(jìn)制格式保存數(shù)據(jù)
>>> f.close()
>>> import os
>>> s1 = os.stat("22902.dat").st_size #得到兩個(gè)文件的大小
>>> s2 = os.stat("22903.dat").st_size
>>> print "%d, %d, %.2f%%" % (s1, s2, (s2+0.0)/s1*100)
68903, 29774, 43.21%
比較結(jié)果發(fā)現(xiàn),以二進(jìn)制方式保存的文件比以ascii格式保存的文件小很多,前者約是后者的43%。
所以,在序列化的時(shí)候,特別是面對(duì)較大對(duì)象時(shí),建議將dump()的參數(shù)True設(shè)置上,雖然現(xiàn)在存儲(chǔ)設(shè)備的價(jià)格便宜,但是能省還是省點(diǎn)比較好。
存入文件,僅是一個(gè)目標(biāo),還有另外一個(gè)目標(biāo),就是要讀出來(lái),也稱之為反序列化。
>>> integers = pickle.load(open("22901.dat", "rb"))
>>> print integers
[1, 2, 3, 4, 5]
就是前面存入的那個(gè)列表。再看看被以二進(jìn)制存入的那個(gè)文件:
>>> f = open("22903.dat", "rb")
>>> d = pickle.load(f)
>>> print d
{'i': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, .... #省略后面的數(shù)字}
>>> f.close()
還是有自己定義數(shù)據(jù)類型的需要,這種類型是否可以用上述方式存入文件并讀出來(lái)呢?看下面的例子:
>>> import cPickle as pickle #cPickle更快
>>> import StringIO #標(biāo)準(zhǔn)庫(kù)中的一個(gè)模塊,跟file功能類似,只不過(guò)是在內(nèi)存中操作“文件”
>>> class Book(object): #自定義一種類型
... def __init__(self,name):
... self.name = name
... def my_book(self):
... print "my book is: ", self.name
...
>>> pybook = Book("<from beginner to master>")
>>> pybook.my_book()
my book is: <from beginner to master>
>>> file = StringIO.StringIO()
>>> pickle.dump(pybook, file, 1)
>>> print file.getvalue() #查看“文件”內(nèi)容,注意下面不是亂碼
ccopy_reg
_reconstructor
q?(c__main__
Book
q?c__builtin__
object
q?NtRq?}qU?nameq?U?<from beginner to master>sb.
>>> pickle.dump(pybook, file) #換一種方式,再看內(nèi)容,可以比較一下
>>> print file.getvalue() #視覺(jué)上,兩者就有很大差異
ccopy_reg
_reconstructor
q?(c__main__
Book
q?c__builtin__
object
q?NtRq?}qU?nameq?U?<from beginner to master>sb.ccopy_reg
_reconstructor
p1
(c__main__
Book
p2
c__builtin__
object
p3
NtRp4
(dp5
S'name'
p6
S'<from beginner to master>'
p7
sb.
如果要從文件中讀出來(lái):
>>> file.seek(0) #找到對(duì)應(yīng)類型
>>> pybook2 = pickle.load(file)
>>> pybook2.my_book()
my book is: <from beginner to master>
>>> file.close()
pickle模塊已經(jīng)表現(xiàn)出它足夠好的一面了。不過(guò),由于數(shù)據(jù)的復(fù)雜性,pickle只能完成一部分工作,在另外更復(fù)雜的情況下,它就稍顯麻煩了。于是,又有了shelve。
shelve模塊也是標(biāo)準(zhǔn)庫(kù)中的。先看一下基本操作:寫入和讀取
>>> import shelve
>>> s = shelve.open("22901.db")
>>> s["name"] = "www.itdiffer.com"
>>> s["lang"] = "python"
>>> s["pages"] = 1000
>>> s["contents"] = {"first":"base knowledge","second":"day day up"}
>>> s.close()
以上完成了數(shù)據(jù)寫入的過(guò)程。其實(shí),這更接近數(shù)據(jù)庫(kù)的樣式了。下面是讀取。
>>> s = shelve.open("22901.db")
>>> name = s["name"]
>>> print name
www.itdiffer.com
>>> contents = s["contents"]
>>> print contents
{'second': 'day day up', 'first': 'base knowledge'}
當(dāng)然,也可以用for語(yǔ)句來(lái)讀:
>>> for k in s:
... print k, s[k]
...
contents {'second': 'day day up', 'first': 'base knowledge'}
lang python
pages 1000
name www.itdiffer.com
不管是寫,還是讀,都似乎要簡(jiǎn)化了。所建立的對(duì)象s,就如同字典一樣,可稱之為類字典對(duì)象。所以,可以如同操作字典那樣來(lái)操作它。
但是,要小心坑:
>>> f = shelve.open("22901.db")
>>> f["author"]
['qiwsir']
>>> f["author"].append("Hetz") #試圖增加一個(gè)
>>> f["author"] #坑就在這里
['qiwsir']
>>> f.close()
當(dāng)試圖修改一個(gè)已有鍵的值時(shí),沒(méi)有報(bào)錯(cuò),但是并沒(méi)有修改成功。要填平這個(gè)坑,需要這樣做:
>>> f = shelve.open("22901.db", writeback=True) #多一個(gè)參數(shù)True
>>> f["author"].append("Hetz")
>>> f["author"] #沒(méi)有坑了
['qiwsir', 'Hetz']
>>> f.close()
還用for循環(huán)一下:
>>> f = shelve.open("22901.db")
>>> for k,v in f.items():
... print k,": ",v
...
contents : {'second': 'day day up', 'first': 'base knowledge'}
lang : python
pages : 1000
author : ['qiwsir', 'Hetz']
name : www.itdiffer.com
shelve更像數(shù)據(jù)庫(kù)了。
不過(guò),它還不是真正的數(shù)據(jù)庫(kù)。真正的數(shù)據(jù)庫(kù)在后面。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: