鍍金池/ 教程/ Python/ 將數(shù)據(jù)存入文件
標(biāo)準(zhǔn)庫 (4)
如何成為 Python 高手
標(biāo)準(zhǔn)庫 (6)
標(biāo)準(zhǔn)庫 (3)
類(2)
Pandas 使用 (2)
xml
用 tornado 做網(wǎng)站 (5)
文件(1)
練習(xí)
列表(3)
從小工到專家
除法
錯(cuò)誤和異常 (2)
函數(shù)(1)
用 tornado 做網(wǎng)站 (7)
為做網(wǎng)站而準(zhǔn)備
函數(shù)練習(xí)
標(biāo)準(zhǔn)庫 (8)
Pandas 使用 (1)
回顧 list 和 str
字典(1)
用 tornado 做網(wǎng)站 (3)
字符串(1)
函數(shù)(2)
寫一個(gè)簡單的程序
將數(shù)據(jù)存入文件
語句(5)
SQLite 數(shù)據(jù)庫
集成開發(fā)環(huán)境(IDE)
集合(1)
類(1)
用 tornado 做網(wǎng)站 (6)
用 tornado 做網(wǎng)站 (2)
自省
語句(4)
錯(cuò)誤和異常 (1)
用 tornado 做網(wǎng)站 (4)
集合(2)
列表(1)
標(biāo)準(zhǔn)庫 (1)
生成器
mysql 數(shù)據(jù)庫 (1)
第三方庫
實(shí)戰(zhàn)
運(yùn)算符
類(3)
字典(2)
語句(1)
數(shù)和四則運(yùn)算
語句(2)
文件(2)
MySQL 數(shù)據(jù)庫 (2)
電子表格
迭代器
mongodb 數(shù)據(jù)庫 (1)
特殊方法 (2)
特殊方法 (1)
字符編碼
編寫模塊
用 tornado 做網(wǎng)站 (1)
標(biāo)準(zhǔn)庫 (5)
函數(shù)(4)
類(5)
字符串(2)
關(guān)于 Python 的故事
函數(shù)(3)
字符串(4)
處理股票數(shù)據(jù)
常用數(shù)學(xué)函數(shù)和運(yùn)算優(yōu)先級(jí)
字符串(3)
為計(jì)算做準(zhǔn)備
多態(tài)和封裝
類(4)
迭代
語句(3)
錯(cuò)誤和異常 (3)
分析 Hello
Python 安裝
標(biāo)準(zhǔn)庫 (2)
列表(2)
元組

將數(shù)據(jù)存入文件

《文件(1)》《文件(2)》中,已經(jīng)學(xué)習(xí)了如何讀寫文件。

如果在程序中,有數(shù)據(jù)要保存到磁盤中,放到某個(gè)文件中是一種不錯(cuò)的方法。但是,如果像以前那樣存,未免有點(diǎn)凌亂,并且沒有什么良好的存儲(chǔ)格式,導(dǎo)致數(shù)據(jù)以后被讀出來的時(shí)候遇到麻煩,特別是不能讓另外的使用者很好地理解。不要忘記了,編程是一個(gè)合作的活。還有,存儲(chǔ)的數(shù)據(jù)不一定都是類似字符串、整數(shù)那種基礎(chǔ)類型的。

總而言之,需要將要存儲(chǔ)的對(duì)象格式化(或者叫做序列化),才好存好取。這就有點(diǎn)類似集裝箱的作用。

所以,要用到本講中提供的方式。

pickle

pickle 是標(biāo)準(zhǔn)庫中的一個(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 中。如果你要打開這個(gè)文件,看里面的內(nèi)容,可能有點(diǎn)失望,但是,它對(duì)計(jì)算機(jī)是友好的。這個(gè)步驟,可以稱之為將對(duì)象序列化。用到的方法是:

pickle.dump(obj,file[,protocol])

  • obj:序列化對(duì)象,上面的例子中是一個(gè)列表,它是基本類型,也可以序列化自己定義的類型。
  • file:一般情況下是要寫入的文件。更廣泛地可以理解為為擁有 write() 方法的對(duì)象,并且能接受字符串為為參數(shù),所以,它還可以是一個(gè) StringIO 對(duì)象,或者其它自定義滿足條件的對(duì)象。
  • protocol:可選項(xiàng)。默認(rèn)為 False(或者說 0),是以 ASCII 格式保存對(duì)象;如果設(shè)置為 1 或者 True,則以壓縮的二進(jìn)制格式保存對(duì)象。

下面換一種數(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),就是要讀出來,也稱之為反序列化。

>>> 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ù)類型的需要,這種類型是否可以用上述方式存入文件并讀出來呢?看下面的例子:

>>> import cPickle as pickle        #cPickle 更快
>>> import StringIO                 #標(biāo)準(zhǔn)庫中的一個(gè)模塊,跟 file 功能類似,只不過是在內(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
qc__builtin__
object
qNtRq}qUnameqU<from beginner to master>sb.

>>> pickle.dump(pybook, file)       #換一種方式,再看內(nèi)容,可以比較一下
>>> print file.getvalue()           #視覺上,兩者就有很大差異
ccopy_reg
_reconstructor
q(c__main__
Book
qc__builtin__
object
qNtRq}qUnameqU<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.

如果要從文件中讀出來:

>>> file.seek(0)       #找到對(duì)應(yīng)類型  
>>> pybook2 = pickle.load(file)
>>> pybook2.my_book()
my book is:  <from beginner to master>
>>> file.close()

shelve

pickle 模塊已經(jīng)表現(xiàn)出它足夠好的一面了。不過,由于數(shù)據(jù)的復(fù)雜性,pickle 只能完成一部分工作,在另外更復(fù)雜的情況下,它就稍顯麻煩了。于是,又有了 shelve。

shelve 模塊也是標(biāo)準(zhǔn)庫中的。先看一下基本操作:寫入和讀取

>>> 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ù)寫入的過程。其實(shí),這更接近數(shù)據(jù)庫的樣式了。下面是讀取。

>>> 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 語句來讀:

>>> for k in s:
...     print k, s[k]
... 
contents {'second': 'day day up', 'first': 'base knowledge'}
lang python
pages 1000
name www.itdiffer.com

不管是寫,還是讀,都似乎要簡化了。所建立的對(duì)象s,就如同字典一樣,可稱之為類字典對(duì)象。所以,可以如同操作字典那樣來操作它。

但是,要小心坑:

>>> f = shelve.open("22901.db")
>>> f["author"]
['qiwsir']
>>> f["author"].append("Hetz")    #試圖增加一個(gè)
>>> f["author"]                   #坑就在這里
['qiwsir']
>>> f.close()

當(dāng)試圖修改一個(gè)已有鍵的值時(shí),沒有報(bào)錯(cuò),但是并沒有修改成功。要填平這個(gè)坑,需要這樣做:

>>> f = shelve.open("22901.db", writeback=True)    #多一個(gè)參數(shù) True
>>> f["author"].append("Hetz")
>>> f["author"]                   #沒有坑了
['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ù)庫了。

不過,它還不是真正的數(shù)據(jù)庫。真正的數(shù)據(jù)庫在后面。


總目錄   |   上節(jié):第三方庫   |   下節(jié):mysql數(shù)據(jù)庫(1)

如果你認(rèn)為有必要打賞我,請(qǐng)通過支付寶:qiwsir@126.com,不勝感激。