【第十二天】Python的文件操作

第五章

5.1存儲(chǔ)

1.文件

我們知道峻呕,py中的數(shù)據(jù)都保存在內(nèi)存中利职,當(dāng)電腦斷電時(shí),就好像患了失憶癥
內(nèi)存中的數(shù)據(jù)就會(huì)消失瘦癌,另一方面猪贪,如果py程序運(yùn)行結(jié)束
那么分配給這個(gè)程序的內(nèi)存空間也會(huì)清空,為了長(zhǎng)期持續(xù)地存儲(chǔ)
py必須把數(shù)據(jù)存儲(chǔ)在磁盤(pán)中讯私,這樣热押,即使斷電或程序結(jié)束
數(shù)據(jù)依然存在

磁盤(pán)以文件為單位來(lái)存儲(chǔ)數(shù)據(jù)西傀,對(duì)于計(jì)算機(jī)來(lái)說(shuō),數(shù)據(jù)的本質(zhì)就是
有序的二進(jìn)制數(shù)序列桶癣,如果以字節(jié)為單位拥褂,也就是每8位二進(jìn)制數(shù)序列為單位
那么這個(gè)數(shù)據(jù)序列就稱(chēng)為文本,這是因?yàn)椋?位的二進(jìn)制數(shù)序列正好
對(duì)應(yīng)ASCII編碼中的一個(gè)字符牙寞,而py能夠借助文本對(duì)象來(lái)讀寫(xiě)文件

在py中饺鹃,我們可以通過(guò)內(nèi)置函數(shù)open來(lái)創(chuàng)建文件對(duì)象
在調(diào)用open時(shí),需要說(shuō)明文件名碎税,以及打開(kāi)文件的方式:

f = open(文件名尤慰,方式)

文件名是文件存在于磁盤(pán)的名字,打開(kāi)文件的常用方式有:

"r" #讀取已經(jīng)存在的文件
"w" #新建文件雷蹂,并寫(xiě)入
"a" #如果文件存在伟端,那么寫(xiě)入到文件的結(jié)尾,如果文件不存在匪煌,則新建文件并寫(xiě)入

例如:

f = open("test.txt","r")

就是用只讀的方式责蝠,打開(kāi)了一個(gè)名為test.txt的文件

通過(guò)返回上面的對(duì)象,我們可以讀取文件:

content = f.read(10)        #讀取10個(gè)字節(jié)的數(shù)據(jù)
content = f.readline()      #讀取一行
content = f.readlines()     #讀取所有行萎庭,儲(chǔ)存在列表中霜医,每個(gè)元素是一行

如果以"w"或"a"方式打開(kāi),那么我們就可以寫(xiě)入文本:

f = open('test.txt','w')
f.write('i like apple')     #將'i like apple'寫(xiě)入文件

如果想寫(xiě)入一行驳规,則需要在字符串末尾加上換行符
在UNIX系統(tǒng)中肴敛,換行符為"\n"
在windows系統(tǒng)中,換行符為"\r\n"

打開(kāi)文件端口將占用計(jì)算機(jī)資源吗购,因此医男,在讀寫(xiě)完成后
應(yīng)該及時(shí)的用文件對(duì)象的close()方法關(guān)閉文件:

f.close()

用法延伸:
r:以只讀方式打開(kāi)文件。文件的指針將會(huì)放在文件的開(kāi)頭捻勉。這是默認(rèn)模式

rb:以二進(jìn)制只讀方式打開(kāi)一個(gè)文件镀梭。文件指針將會(huì)放在文件的開(kāi)頭

r+:以讀寫(xiě)方式打開(kāi)一個(gè)文件。文件指針將會(huì)放在文件的開(kāi)頭

rb+:以二進(jìn)制讀寫(xiě)方式打開(kāi)一個(gè)文件踱启。文件指針將會(huì)放在文件的開(kāi)頭

w:以寫(xiě)入方式打開(kāi)一個(gè)文件报账。如果該文件已存在,則將其覆蓋埠偿。如果該文件不存在透罢,則創(chuàng)建新文件。

wb:以二進(jìn)制寫(xiě)入方式打開(kāi)一個(gè)文件胚想。如果該文件已存在琐凭,則將其覆蓋。如果該文件不存在浊服,則創(chuàng)建新文件统屈。

w+:以讀寫(xiě)方式打開(kāi)一個(gè)文件胚吁。如果該文件已存在,則將其覆蓋愁憔。如果該文件不存在腕扶,則創(chuàng)建新文件。

wb+:以二進(jìn)制讀寫(xiě)格式打開(kāi)一個(gè)文件吨掌。如果該文件已存在半抱,則將其覆蓋。如果該文件不存在膜宋,則創(chuàng)建新文件窿侈。

a:以追加方式打開(kāi)一個(gè)文件。如果該文件已存在秋茫,文件指針將會(huì)放在文件結(jié)尾史简。
也就是說(shuō),新的內(nèi)容將會(huì)被寫(xiě)入到已有內(nèi)容之后肛著。如果該文件不存在圆兵,則創(chuàng)建新文件來(lái)寫(xiě)入。

ab:以二進(jìn)制追加方式打開(kāi)一個(gè)文件枢贿。如果該文件已存在殉农,則文件指針將會(huì)放在文件結(jié)尾。
也就是說(shuō)局荚,新的內(nèi)容將會(huì)被寫(xiě)入到已有內(nèi)容之后超凳。如果該文件不存在,則創(chuàng)建新文件來(lái)寫(xiě)入耀态。

a+:以讀寫(xiě)方式打開(kāi)一個(gè)文件聪建。如果該文件已存在,文件指針將會(huì)放在文件的結(jié)尾茫陆。
文件打開(kāi)時(shí)會(huì)是追加模式。如果該文件不存在擎析,則創(chuàng)建新文件來(lái)讀寫(xiě)簿盅。

ab+:以二進(jìn)制追加方式打開(kāi)一個(gè)文件。如果該文件已存在揍魂,則文件指針將會(huì)放在文件結(jié)尾桨醋。
如果該文件不存在,則創(chuàng)建新文件用于讀寫(xiě)现斋。

來(lái)源鏈接:https://juejin.im/post/5ab22accf265da239a5fb172

2.上下文管理器

文件操作常常和上下文管理器一起使用喜最,上下文管理器(context manager)
用于規(guī)定某個(gè)對(duì)象的使用范圍,一旦進(jìn)入或者離開(kāi)該使用范圍庄蹋,則會(huì)有特殊操作被調(diào)用
比如為對(duì)象分配或者釋放內(nèi)存瞬内,上下文管理器可用于文件操作迷雪,對(duì)于文件操作來(lái)說(shuō)
我們需要在讀寫(xiě)結(jié)束時(shí)關(guān)閉文件,程序員經(jīng)常會(huì)忘記關(guān)閉文件虫蝶,無(wú)謂占用資源
上下文管理器可以在不需要文件的時(shí)候章咧,自動(dòng)關(guān)閉文件

下面時(shí)一段常規(guī)的文件操作程序:

#常規(guī)文件操作

f = open("new.txt","w")
print(f.closed)            #檢查文件是否打開(kāi)
f.write("hello world!")
f.close()
print(f.closed)            #打印True

如果我們加入上下文管理器的語(yǔ)法,就可以把程序改寫(xiě)為:

#使用上下文管理器

with open("new.txt","w") as f:
    f.write("hello world!")
print(f.closed)

第二段程序就使用了with...as...結(jié)構(gòu)能真,上下文管理器有隸屬于它的程序塊
當(dāng)隸屬的程序塊執(zhí)行結(jié)束時(shí)赁严,也就是語(yǔ)句不再縮進(jìn)時(shí),上下文管理器就會(huì)自動(dòng)關(guān)閉文件
在程序中粉铐,我們調(diào)用了f.closed屬性來(lái)驗(yàn)證是否已經(jīng)關(guān)閉
通過(guò)上下文管理器疼约,我們相當(dāng)于用縮進(jìn)來(lái)表達(dá)文件對(duì)象的打開(kāi)范圍
對(duì)于復(fù)雜的程序來(lái)說(shuō),縮進(jìn)的存在能讓程序員更清楚的意識(shí)到文件在哪些階段打開(kāi)
減少忘記關(guān)閉文件的可能性

上面的上下文管理器基于f對(duì)象的exit()特殊方法
使用上下文管理器的語(yǔ)法時(shí)蝙泼,py會(huì)在進(jìn)入程序塊之前調(diào)用文件對(duì)象的enter()方法
在結(jié)束程序塊的時(shí)候調(diào)用文件對(duì)象的exit()方法
在文件對(duì)象的exit()中程剥,有self.close()語(yǔ)句
因此,在使用上下文管理器時(shí)踱承,我們就不必用明文關(guān)閉文件了

任何定義了enter()方法和exit()的對(duì)象都可以用于上下文管理器
下面倡缠,我們自定義一個(gè)類(lèi)Vow,并定義它的enter()方法和exit()方法
因此,由Vow類(lèi)的對(duì)象可以用于上下文管理器:

class Vow(object):
    def __init__(self,text):
        self.text = text
    def __enter__(self):
        self.text = "i say:" + self.text    #增加前綴
        return self                         #返回一個(gè)對(duì)象
    def __exit__(self,exc_type,exc_value,traceback):
        self.text = self.text + "!"         #增加后綴
with Vow("I'm fine") as myVow:
    print(myVow.text)
    
print(myVow.text)
i say:I'm fine
i say:I'm fine!

初始化對(duì)象時(shí)茎活,對(duì)象的text屬性是"I'm fine"我們可以看到
在進(jìn)入上下文和離開(kāi)上下文時(shí)昙沦,對(duì)象調(diào)用了enter()方法和exit()方法
從而造成對(duì)象的text屬性改變

enter()返回一個(gè)對(duì)象,上下文管理器會(huì)使用這一對(duì)象作為as所指變量
我們自定義的enter()返回的是self载荔,也就是新建的Vow類(lèi)對(duì)象本身
enter()中盾饮,我們?yōu)閠ext屬性增加了前綴"i say:"
exit()中,我們?yōu)閠ext屬性增加后綴"!"

值得注意的是懒熙,exit()有四個(gè)參數(shù)丘损,當(dāng)程序塊中出現(xiàn)異常時(shí)
exit()參數(shù)中exc_type,exc_value,traceback用于描述異常
我們可以根據(jù)這三個(gè)參數(shù)進(jìn)行相應(yīng)的處理,如果正常運(yùn)行結(jié)束工扎,則這三個(gè)參數(shù)都是None

3.pickle包

我們能把文本存于文件徘钥,但py中最常見(jiàn)的是對(duì)象,當(dāng)程序結(jié)束或者計(jì)算機(jī)關(guān)閉時(shí)
這些存在于內(nèi)存的對(duì)象會(huì)消失肢娘,那么呈础,我們能否把對(duì)象保存在磁盤(pán)上呢

利用pickle包就可以做到這一點(diǎn),英文里橱健,pickle是腌菜的意思
大航海時(shí)代的海員們常把蔬菜做成腌菜而钞,裝在罐頭里帶著走
py中的pickle也有類(lèi)似的意思,通過(guò)pickle包拘荡,我們可以把某個(gè)對(duì)象保存下來(lái)
再存成磁盤(pán)里的文件

實(shí)際上臼节,對(duì)象的存儲(chǔ)分為兩步,第一步,我們將對(duì)象在內(nèi)存里的數(shù)據(jù)直接抓取出來(lái)
轉(zhuǎn)換成一個(gè)有序的文本网缝,即所謂的序列化(Serialization),第二步
將文本存入文件巨税,等到需要時(shí),我們從文件中讀出文本途凫,再放入內(nèi)存
就可以獲得原有的對(duì)象垢夹,下面是一個(gè)具體的例子
首先是第一步序列化,將內(nèi)存中的對(duì)象轉(zhuǎn)換為文本流:

import pickle
class Bird(object):
    have_feather = True
    reproduction_method = 'egg'
summer = Bird()                          #創(chuàng)建對(duì)象
pickle_string = pickle.dumps(summer)     #序列化對(duì)象

使用pickle包的dumps()方法可以將對(duì)象轉(zhuǎn)換成字符串的形式
隨后维费,我們用字節(jié)文本的存儲(chǔ)方法果元,將該字符串儲(chǔ)存在文件
繼續(xù)第二步

with open("summer.pkl","wb") as f:
    f.write(pickle_string)

上面程序故意分成了兩步,以便更好的展示整個(gè)過(guò)程
其實(shí)犀盟,我們可以使用dump()的方法而晒,一次完成兩步:

import pickle

class Bird(object):
    have_feather = True
    reproduction_method = 'egg'
summer = Bird()                 
with open("summer.pkl","wb") as f:
    pickle.dump(summer,f)         #有序化并保存對(duì)象

對(duì)象summer將存儲(chǔ)在文件summer.pkl中
有了這個(gè)文件,我們就可以在必要的時(shí)候讀取對(duì)象了
讀取對(duì)象與存儲(chǔ)對(duì)象的過(guò)程正好相反阅畴,首先倡怎,我們從文件中讀取文本
然后使用pickle的loads()方法,將字符串形式的文本轉(zhuǎn)換為對(duì)象
我們也可以使用pickle的load()方法贱枣,將上面兩步合并

有的時(shí)候监署,僅僅是反向恢復(fù)還不夠,對(duì)象依賴(lài)于它的類(lèi)
所以py在創(chuàng)建對(duì)象時(shí)纽哥,需要找到相應(yīng)的類(lèi)
因此當(dāng)我們從文本中讀取對(duì)象時(shí)钠乏,程序中必須已經(jīng)定義過(guò)類(lèi)
對(duì)于py總是存在的內(nèi)置類(lèi),如列表春塌,詞典晓避,字符串等
不需要再在程序中定義,但是對(duì)于用戶(hù)自定義的類(lèi)只壳,就必須要先定義類(lèi)
然后才能在文件中載入該類(lèi)的對(duì)象
下面是一個(gè)讀取對(duì)象的例子:

import pickle

class Bird(object):
    have_feather = True
    reproduction_method = 'egg'
summer = Bird()                 
with open("summer.pkl","rb") as f:
    summer = pickle.load(f)
print(summer.have_feather)       #打印True     

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末俏拱,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子吼句,更是在濱河造成了極大的恐慌锅必,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件惕艳,死亡現(xiàn)場(chǎng)離奇詭異况毅,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)尔艇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)么鹤,“玉大人终娃,你說(shuō)我怎么就攤上這事≌籼穑” “怎么了棠耕?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵余佛,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我窍荧,道長(zhǎng)辉巡,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任蕊退,我火速辦了婚禮郊楣,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘瓤荔。我一直安慰自己净蚤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布输硝。 她就那樣靜靜地躺著今瀑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪点把。 梳的紋絲不亂的頭發(fā)上橘荠,一...
    開(kāi)封第一講書(shū)人閱讀 49,079評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音郎逃,去河邊找鬼哥童。 笑死,一個(gè)胖子當(dāng)著我的面吹牛衣厘,可吹牛的內(nèi)容都是我干的如蚜。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼影暴,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼错邦!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起型宙,我...
    開(kāi)封第一講書(shū)人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤撬呢,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后妆兑,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體魂拦,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年搁嗓,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了芯勘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡腺逛,死狀恐怖荷愕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤安疗,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布抛杨,位于F島的核電站,受9級(jí)特大地震影響荐类,放射性物質(zhì)發(fā)生泄漏怖现。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一玉罐、第九天 我趴在偏房一處隱蔽的房頂上張望屈嗤。 院中可真熱鬧,春花似錦厌小、人聲如沸恢共。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)讨韭。三九已至,卻和暖如春癣蟋,著一層夾襖步出監(jiān)牢的瞬間透硝,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工疯搅, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留濒生,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓幔欧,卻偏偏與公主長(zhǎng)得像罪治,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子礁蔗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345