我們來讀取這樣一個(gè)文本文件:song.txt,該文件的字符編碼為utf-8。
匆匆那年我們究竟說了幾遍再見之后再拖延
可惜誰有沒有愛過不是一場(chǎng)七情上面的雄辯
匆匆那年我們一時(shí)匆忙撂下難以承受的諾言
只有等別人兌現(xiàn)
1.菜鳥實(shí)現(xiàn)(只是實(shí)現(xiàn)功能):
python3實(shí)現(xiàn):
#第一步:(以只讀模式)打開文件
f=open('song.txt','r',encoding='utf-8')
#第二步:讀取文件內(nèi)容
print(f.read())
#第三步:關(guān)閉文件
f.close()
這里說下Python2的實(shí)現(xiàn)
#第一步:(以只讀模式)打開文件
f=open('song.txt','r')
#第二步:讀取文件內(nèi)容
print(f.read().decode('utf-8'))
#第三步:關(guān)閉文件
f.close()
說明:
Python3中已經(jīng)內(nèi)置對(duì)Unicode的支持,字符串str已經(jīng)是真正的Unicode字符串。也就是說Python3中的文件讀取方法已經(jīng)自動(dòng)完成了解碼處理,因此無需再手動(dòng)進(jìn)行解碼,可以直接將讀取的文件中的內(nèi)容進(jìn)行打印;Python2中的字符串str是字節(jié)串,讀取文件得到的也是字節(jié)串,在打印之前應(yīng)該手動(dòng)將其解碼成Unicode字符串。關(guān)于這部分的說明,可以參考之前這篇文章<<再談Python中的字符串與字符編碼>>。
2.中級(jí)實(shí)現(xiàn)
在實(shí)現(xiàn)基本功能的前提下,考慮一些可能的意外因素。因?yàn)槲募x寫時(shí)都有可能產(chǎn)生IO錯(cuò)誤(IOError),一旦出錯(cuò),后面包括f.close()在內(nèi)的所有代碼都不會(huì)執(zhí)行了。因此我們要保證文件無論如何都能被關(guān)閉。那么可以用try...finally來實(shí)現(xiàn),這實(shí)際上就是try...except..finally的簡(jiǎn)化版(我們只用Python3來進(jìn)行示例演示):
f=''
try:
f=open('song.txt','r',encoding='utf-8')
print(f.read())
num=10/0
finally:
print('>>>>>>finally')
iff:
f.close()
輸出結(jié)果:
匆匆那年我們究竟說了幾遍再見之后再拖延
可惜誰有沒有愛過不是一場(chǎng)七情上面的雄辯
匆匆那年我們一時(shí)匆忙撂下難以承受的諾言
只有等別人兌現(xiàn)
>>>>>>finally
Traceback(mostrecentcalllast):
File"",line4,in
ZeroDivisionError:divisionbyzero
輸出結(jié)果說明,盡管with代碼塊中出現(xiàn)了異常,但是”>>>>>>finally“信息還是被打印了,說明finally代碼塊被執(zhí)行,即文件關(guān)閉操作被執(zhí)行。但是結(jié)果中錯(cuò)誤信息還是被輸出了,因此還是建議用一個(gè)完成的try...except...finally語句對(duì)異常信息進(jìn)行捕獲和處理。
3.最佳實(shí)踐
為了避免忘記或者為了避免每次都要手動(dòng)關(guān)閉文件,我們可以使用with語句(一種語法糖,語法糖語句通常是為了簡(jiǎn)化某些操作而設(shè)計(jì)的)。with語句會(huì)在其代碼塊執(zhí)行完畢之后自動(dòng)關(guān)閉文件。因此我們可以這樣來改寫上面的程序:
withopen('song.txt','r',encoding='utf-8')asf:
print(f.read())
print(f.closed)
輸出結(jié)果:
匆匆那年我們究竟說了幾遍再見之后再拖延
可惜誰有沒有愛過不是一場(chǎng)七情上面的雄辯
匆匆那年我們一時(shí)匆忙撂下難以承受的諾言
只有等別人兌現(xiàn)
True
是不是變得簡(jiǎn)介多了,代碼結(jié)構(gòu)也比較清晰了。with之后打印的f.closed屬性值為True,說明文件確實(shí)被關(guān)閉了。
思考:
with語句會(huì)幫我們自動(dòng)處理異常信息嗎?
要回答這個(gè)問題就要提到“上下文管理器”和with語句的工作流程。
with語句不僅僅可以用于文件操作,它實(shí)際上是一個(gè)很通用的結(jié)構(gòu),允許使用所謂的上下文管理器(contextmanager)。上下文管理器是一種支持__enter__()和__exit__()這兩個(gè)方法的對(duì)象。__enter__()方法不帶任何參數(shù),它在進(jìn)入with語句塊的時(shí)候被調(diào)用,該方法的返回值會(huì)被賦值給as關(guān)鍵字之后的變量。__exit__()方法帶有3個(gè)參數(shù):type(異常類型),value(異常信息),trace(異常棧),當(dāng)with語句的代碼塊執(zhí)行完畢或執(zhí)行過程中因?yàn)楫惓6唤K止都會(huì)調(diào)用__exit__()方法。正常退出時(shí)該方法的3個(gè)參數(shù)都為None,異常退出時(shí)該方法的3個(gè)參數(shù)會(huì)被分別賦值。如果__exit__()方法返回值(真值測(cè)試結(jié)果)為True則表示異常已經(jīng)被處理,命令執(zhí)行結(jié)果中就不會(huì)拋出異常信息了;反之,如果__exit__()方法返回值(真值測(cè)試結(jié)果)為False,則表示異常沒有被處理并且會(huì)向外拋出該異常。
現(xiàn)在我們應(yīng)該明白了,異常信息會(huì)不會(huì)被處理是由with后的語句返回對(duì)象的__exit__()方法決定的。文件可以被用作上下文管理器。它的__enter__方法返回文件對(duì)象本身,__exit__方法會(huì)關(guān)閉文件并返回None。我們看下file類中關(guān)于這兩個(gè)方法的實(shí)現(xiàn):
def__enter__(self):#realsignatureunknown;restoredfrom__doc__
"""__enter__()->self."""
returnself
def__exit__(self,*excinfo):#realsignatureunknown;restoredfrom__doc__
"""__exit__(*excinfo)->None.Closesthefile."""
pass
可見,file類的__exit__()方法的返回值為None,None的真值測(cè)試結(jié)果為False,因此用于文件讀寫的with語句代碼塊中的異常信息還是會(huì)被拋出來,需要我們自己去捕獲并處理。
withopen('song.txt','r',encoding='utf-8')asf:
print(f.read())
num=10/0
輸出結(jié)果:
匆匆那年我們究竟說了幾遍再見之后再拖延
可惜誰有沒有愛過不是一場(chǎng)七情上面的雄辯
匆匆那年我們一時(shí)匆忙撂下難以承受的諾言
只有等別人兌現(xiàn)
Traceback(mostrecentcalllast):
File"",line3,in
ZeroDivisionError:divisionbyzero
注意:上面所說的__exit__()方法返回值(真值測(cè)試結(jié)果)為True則表示異常已經(jīng)被處理,指的是with代碼塊中出現(xiàn)的異常。它對(duì)于with關(guān)鍵字之后的代碼中出現(xiàn)的異常是不起作用的,因?yàn)檫€沒有進(jìn)入上下文管理器就已經(jīng)發(fā)生異常了。因此,無論如何,還是建議在必要的時(shí)候在with語句外面套上一層try...except來捕獲和處理異常。
有關(guān)“上下文管理器”這個(gè)強(qiáng)大且高級(jí)的特性的更多信息,請(qǐng)參看Python參考手冊(cè)中的上下文管理器部分。或者可以在Python庫(kù)參考中查看上下文管理器和contextlib部分。
以上內(nèi)容為大家介紹了Python文件操作步驟示例,希望對(duì)大家有所幫助,如果想要了解更多Python相關(guān)知識(shí),請(qǐng)關(guān)注IT培訓(xùn)機(jī)構(gòu):千鋒教育。