您好,登錄后才能下訂單哦!
這篇文章主要講解了“Python初學(xué)者必備的文件讀寫(xiě)方法”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“Python初學(xué)者必備的文件讀寫(xiě)方法”吧!
?先,我們來(lái)看看下?這段代碼,并思考:這段代碼有沒(méi)有問(wèn)題,如果有問(wèn)題的話,要怎么改?
li = ['python',' is',' a',' cat'] with open('test.txt','w') as f: f.write(li)
現(xiàn)在公布答案,這段代碼會(huì)報(bào)錯(cuò):
TypeError Traceback (most recent call last) <ipython-input-6-57e0c2f5a453> in <module>() 1 with open('test.txt','w') as f: ----> 2 f.write(li) TypeError: write() argument must be str, not list
以上代碼的想法是將list列表內(nèi)容寫(xiě)?txt?件中,但是報(bào)錯(cuò) TypeError: write() argument must be str。
就是說(shuō),write()?法必須接受字符串(str)類(lèi)型的參數(shù)。 Python中內(nèi)置了str()?法,可以返回字符串版本的對(duì)象(Return a string version of object)。所以,上?的例?中,我們?cè)囋嚢?f.write(li) 改為 f.write(str(li)) ,先做?下字符串類(lèi)型的轉(zhuǎn)化看看。代碼略。 這次沒(méi)有報(bào)錯(cuò)了,但是打開(kāi)?件就傻眼了吧,寫(xiě)?的內(nèi)容是“['python',' is',' a',' cat']”。怎么才能寫(xiě) 成“python is a cat”呢? ?件寫(xiě)操作還有?個(gè)writelines()?法,它接收的參數(shù)是由字符串組成的序列(sequence),實(shí)際寫(xiě)?的效果是將全部字符串拼接在?起。字符串本身也是?種序列,所以當(dāng)參數(shù)是字符串的時(shí)候,writelines()?法等價(jià)于write()。
# 以下3種寫(xiě)法等價(jià),都是寫(xiě)?字符串“python is a cat” In [20]: with open('test.txt','w') as f: ...: f.writelines(['python',' is',' a',' cat']) ...: f.writelines('python is a cat') ...: f.write('python is a cat') # 以下2種寫(xiě)法等價(jià),都是寫(xiě)?列表的字符串版本“['python',' is',' a',' cat']” In [21]: with open('test.txt','w') as f: ...: f.write(str(['python',' is',' a',' cat'])) ...: f.writelines(str(['python',' is',' a',' cat'])) # 作為反例,以下寫(xiě)法都是錯(cuò)誤的: In [22]: with open('test.txt','w') as f: ...: f.writelines([2018,'is','a','cat']) # 含?字符串 ...: f.write(['python','is','a','cat']) # ?字符串
由上可知,當(dāng)多段分散的字符串存在于列表中的時(shí)候,要?writelines()?法,如果字符串是?整段,那直 接使?write()?法。如果要以整個(gè)列表的形式寫(xiě)??件,就使?str()?法做下轉(zhuǎn)化。 這個(gè)問(wèn)題還沒(méi)結(jié)束,如果列表中就是有元素不是字符串,?且要把全部元素取出來(lái),怎么辦呢? 那就不能直接使?write()和writelines()了,需要先?for循環(huán),把每個(gè)元素取出來(lái),逐?str()處理。
In [37]: content=[1,' is',' everything'] In [38]: with open('test.txt','w') as f: ...: for i in content: ...: f.write(str(i))
需要注意的是,writelines()不會(huì)?動(dòng)換?。如果要實(shí)現(xiàn)列表元素間的換?,?個(gè)辦法是在每個(gè)元素后?加 上換?符“\n”,如果不想改變?cè)?,最好?for循環(huán),在寫(xiě)?的時(shí)候加在末尾:for i in content: f.writelines(str(i)+“\n”) 引申?下,經(jīng)過(guò)實(shí)驗(yàn),數(shù)字及元祖類(lèi)型也可以作為write()的參數(shù),不需轉(zhuǎn)化。但是dict字典類(lèi)型不可以, 需要先?str()處理?下。字典類(lèi)型?較特殊,最好是?json.dump()?法寫(xiě)到?件。 總結(jié)?下,write()接收字符串參數(shù),適?于?次性將全部?jī)?nèi)容寫(xiě)??件;writelines()接收參數(shù)是由字符串 組成的序列,適?于將列表內(nèi)容逐?寫(xiě)??件。str()返回Python對(duì)象的字符串版本,使?需注意。
從?件中讀取內(nèi)容有如下?法:
file.read([size]) 從?件讀取指定的字節(jié)數(shù),如果未給定或?yàn)樨?fù)則讀取所有。 file.readline([size]) 讀取整?,包括 "\n" 字符。 file.readlines([sizeint]) 讀取所有?并返回列表,若給定sizeint>0,則是設(shè)置?次讀多少字節(jié),這是為了減輕讀取壓?。
簡(jiǎn)??之,在不傳參數(shù)的情況下,read()對(duì)應(yīng)write(),讀取全部?jī)?nèi)容;readlines()對(duì)應(yīng)writelines(),讀取 全部?jī)?nèi)容(含換?符)并以列表形式返回,每個(gè)換?的內(nèi)容作為列表的?個(gè)元素。
In [47]: with open('test.txt','r') as f: ...: print(f.read()) 1 is everything. python is a cat. this is the end. In [48]: with open('test.txt','r') as f: ...: print(f.readlines()) ['1 is everything.\n', 'python is a cat.\n', 'this is the end.']
但是,以上兩個(gè)?法有個(gè)缺點(diǎn),當(dāng)?件過(guò)?的時(shí)候,?次性讀取太多內(nèi)容,會(huì)對(duì)內(nèi)存造成極?壓?。讀操作還有?個(gè)readline()?法,可以逐?讀取。
In [49]: with open('test.txt','r') as f: ...: print(f.readline()) 1 is everything.
readline()讀取第??就返回,再次調(diào)?f.readline(),會(huì)讀取下??。 這么看來(lái),readline()太笨拙了。那么,有什么辦法可以優(yōu)雅地讀取?件內(nèi)容呢? 回過(guò)頭來(lái)看readlines()?法,它返回的是?個(gè)列表。這不奇怪么,好端端的內(nèi)容為啥要返回成列表呢? 再想想writelines()?法,把字符串列表寫(xiě)??件正是這家伙?的事,readlines()?法恰恰是它的逆操作! ?writelines()?法要配合for循環(huán),所以我們把readlines()與for循環(huán)結(jié)合,看看會(huì)怎樣。
In [61]: with open('test.txt','r') as f: ...: for line in f.readlines(): ...: print(line) 1 is everything. python is a cat. this is the end. # 讀取內(nèi)容包含換?符,所以要strip()去掉換?符 In [62]: with open('test.txt','r') as f: ...: for line in f.readlines(): ...: print(line.strip()) 1 is everything. python is a cat. this is the end.
總結(jié)?下,readline()?較雞肋,不咋?;read()適合讀取內(nèi)容較少的情況,或者是需要?次性處理全部?jī)?nèi)容的情況;?readlines()?的較多,?較靈活,因?yàn)閒or循環(huán)是?種迭代器,每次加載部分內(nèi)容,既減少內(nèi) 存壓?,??便逐?對(duì)數(shù)據(jù)處理。
前兩部分講了?件讀寫(xiě)的??核??法,它們能夠起作?的前提就是,需要先打開(kāi)?個(gè)?件對(duì)象,因?yàn)橹挥性?件操作符的基礎(chǔ)上才可以進(jìn)?讀或者寫(xiě)的操作。 打開(kāi)?件?的是open()?法,所以我們?cè)倮^續(xù)講講這個(gè)?法。open() ?法?于打開(kāi)?個(gè)?件,并返回?件對(duì)象,在對(duì)?件進(jìn)?處理過(guò)程都需要使?到這個(gè)函數(shù),如果該?件?法被打開(kāi),會(huì)拋出 OSError。
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
open()?法的參數(shù)?file(?件)是必需的,其它參數(shù)最常?的是mode(模式)和encoding(編碼)。 先說(shuō)說(shuō)encoding,?般來(lái)說(shuō),打開(kāi)?件的編碼?式以操作系統(tǒng)的默認(rèn)編碼為準(zhǔn),中?可能會(huì)出現(xiàn)亂碼,需要加encoding='utf-8'。
In [63]: with open('test.txt','r') as f: ...: for line in f.readlines(): ...: print(line.strip()) ----------------------- UnicodeDecodeError Traceback (most recent call last) <ipython-input-63-731a4f9cf707> in <module>() 1 with open('test.txt','r') as f: ----> 2 for line in f.readlines(): 3 print(line.strip()) UnicodeDecodeError: 'gbk' codec can't decode byte 0xa4 in positio n 26: illegal multibyte sequence In [65]: with open('test.txt','r',encoding='utf-8') as f: ...: for line in f.readlines(): ...: print(line.strip()) python is a cat.
再說(shuō)mode,它指定?件打開(kāi)的模式。
r': 以只讀模式打開(kāi)(缺省模式)(必須保證?件存在)
'w':以只寫(xiě)模式打開(kāi)。若?件存在,則清空?件,然后重新創(chuàng)建;若不存在,則新建?件。
'a':以追加模式打開(kāi)。若?件存在,則會(huì)追加到?件的末尾;若?件不存在,則新建?件。
常?的mode組合
'r'或'rt': 默認(rèn)模式,?本讀模式
'w'或'wt': 以?本寫(xiě)模式打開(kāi)(打開(kāi)前?件會(huì)被清空)
'rb': 以?進(jìn)制讀模式打開(kāi) 'ab': 以?進(jìn)制追加模式打開(kāi)
'wb': 以?進(jìn)制寫(xiě)模式打開(kāi)(打開(kāi)前?件會(huì)被清空)
'r+': 以?本讀寫(xiě)模式打開(kāi),默認(rèn)寫(xiě)的指針開(kāi)始指在?件開(kāi)頭, 因此會(huì)覆寫(xiě)?件
'w+': 以?本讀寫(xiě)模式打開(kāi)(打開(kāi)前?件會(huì)被清空)
'a+': 以?本讀寫(xiě)模式打開(kāi)(寫(xiě)只能寫(xiě)在?件末尾)
'rb+': 以?進(jìn)制讀寫(xiě)模式打開(kāi)
'wb+': 以?進(jìn)制讀寫(xiě)模式打開(kāi)(打開(kāi)前?件會(huì)被清空)
'ab+': 以?進(jìn)制讀寫(xiě)模式打開(kāi)
初看起來(lái),模式很多,但是,它們只是相互組合罷了。建議記住最基本的w、r、a,遇到特殊場(chǎng)景,再翻看?下就好了。
基礎(chǔ)部分講完了,下?是進(jìn)階部分。知其然,更要知其所以然。
1、with語(yǔ)句是初學(xué)者必會(huì)常識(shí)
?先,要解釋?下為啥前?直接就?了with語(yǔ)句。with語(yǔ)句是讀寫(xiě)?件時(shí)的優(yōu)雅寫(xiě)法,這已經(jīng)默認(rèn)是Python初學(xué)者必會(huì)的常識(shí)了。如果你還不會(huì),先看看?和不?with語(yǔ)句的對(duì)?:
# 不?with語(yǔ)句的正確寫(xiě)法 try: f = open('test.txt','w') f.writelines(['python',' is',' a',' cat']) finally: if f: f.close() # 使?with語(yǔ)句的正確寫(xiě)法 with open('test.txt','w') as f: f.writelines(['python',' is',' a',' cat'])
因?yàn)?件對(duì)象會(huì)占?操作系統(tǒng)的資源,并且操作系統(tǒng)同?時(shí)間能打開(kāi)的?件數(shù)量是有限的,所以open()?法之后?定要調(diào)?close()?法。另外,讀寫(xiě)操作可能出現(xiàn)IO異常的情況,所以要加try...finally,保證?論如何,都會(huì)調(diào)?到close()?法。 這樣寫(xiě)萬(wàn)??失,但是實(shí)在繁瑣,?不??還可能漏寫(xiě)或者寫(xiě)錯(cuò)。?with語(yǔ)句會(huì)保證調(diào)?close(),只需??代碼,簡(jiǎn)直不要太優(yōu)雅!所以,with語(yǔ)句是Python初學(xué)者必會(huì)技能。
2、什么是上下?管理器?
下?,重頭戲來(lái)了,什么是上下?管理器(context manager)?
上下?管理器是這樣?個(gè)對(duì)象:它定義程序運(yùn)?時(shí)需要建?的上下?,處理程序的進(jìn)?和退出,實(shí)現(xiàn)了上下?管理協(xié)議,即在對(duì)象中定義了 __enter__() 和 __exit__() ?法。 __enter__():進(jìn)?運(yùn)?時(shí)的上下?,返回運(yùn)?時(shí)上下?相關(guān)的對(duì)象,with 語(yǔ)句中會(huì)將這個(gè)返回值綁定到?標(biāo)對(duì)象。 __exit__(exception_type, exception_value, traceback):退出運(yùn)?時(shí)的上下?,定義在塊執(zhí)?(或終?)之后上下?管理器應(yīng)該做什么。它可以處理異常、清理現(xiàn)場(chǎng)或者處理 with 塊中語(yǔ)句執(zhí)?完成之后需要處理的動(dòng)作。
注意 enter 和 exit 的前后有兩個(gè)下劃線,Python 中?帶了很多類(lèi)似的?法,它們是很神秘?很強(qiáng)?的存在,江湖?常常稱其為“?魔法”。例如,迭代器協(xié)議就實(shí)現(xiàn)了__iter__?法。 在Python的內(nèi)置類(lèi)型中,很多類(lèi)型都是?持上下?管理協(xié)議的,例如 file、thread.LockType、 threading.Lock 等等。上下?管理器?法獨(dú)?使?,它們要與 with 相結(jié)合,with 語(yǔ)句可以在代碼塊運(yùn)?前進(jìn)??個(gè)運(yùn)?時(shí)上下?(執(zhí)?__enter__?法),并在代碼塊結(jié)束后退出該上下?(執(zhí)?__exit__?法)。 with 語(yǔ)句適?于對(duì)資源進(jìn)?訪問(wèn)的場(chǎng)合,確保不管使?過(guò)程中是否發(fā)?異常都會(huì)執(zhí)?必要的“清理”操作,釋放資源,?如?件使?后?動(dòng)關(guān)閉、線程中鎖的?動(dòng)獲取和釋放等。
3、?定義上下?管理器
除了Python的內(nèi)置類(lèi)型,任何?都可以定義??的上下?管理器。下?是?個(gè)示例:
class OpenFile(object): def __init__(self,filename,mode): def open_file(name): ff = open(name, 'w') ff.write("enter now\n") try: yield ff except RuntimeError: pass ff.write("exit now") ff.close() with open_file('test.txt') as f: f.write('Hello World!\n')
最終寫(xiě)??件的結(jié)果是:
enter now Hello World! exit now
上下?管理器必須同時(shí)提供 enter() 和 exit() ?法的定義,缺少任何?個(gè)都會(huì)導(dǎo)致 AttributeError。 上下?管理器在執(zhí)?過(guò)程中可能會(huì)出現(xiàn)異常,exit() 的返回值會(huì)決定異常的處理?式:返回值等于 False,那么這個(gè)異常將被重新拋出到上層;返回值等于 True,那么這個(gè)異常就被忽略,繼續(xù)執(zhí)?后?的代碼。exit() 有三個(gè)參數(shù)(exception_type, exception_value, traceback),即是異常的相關(guān)信息。
4、contextlib實(shí)現(xiàn)上下?管理器
上例中,?定義上下?管理器的寫(xiě)法還是挺繁瑣的,?且只能?于類(lèi)級(jí)別。為了更好地輔助上下?管理,Python 內(nèi)置提供了 contextlib 模塊,進(jìn)?可以很?便地實(shí)現(xiàn)函數(shù)級(jí)別的上下?管理器。 該模塊本質(zhì)上是通過(guò)裝飾器(decorators)和?成器(generators)來(lái)實(shí)現(xiàn)上下?管理器,可以直接作?于函數(shù)/對(duì)象,?不?去關(guān)? enter() 和 exit() ?法的具體實(shí)現(xiàn)。 先把上?的例?改造?下,然后我們?cè)賹?duì)照著解釋:
from contextlib import contextmanager @contextmanager def open_file(name): ff = open(name, 'w') ff.write("enter now\n") try: yield ff except RuntimeError: pass ff.write("exit now") ff.close() with open_file('test.txt') as f: f.write('Hello World!\n')
contextmanager 是要使?的裝飾器,yield 關(guān)鍵字將普通的函數(shù)變成了?成器。yield 的返回值(ff)等于上例__enter__()的返回值,也就是 as 語(yǔ)句的值(f),? yield 前后的內(nèi)容,分別是__enter__() 和__exit__() ?法?的內(nèi)容。 使? contextlib,可以避免類(lèi)定義、__enter__() 和 __exit__() ?法,但是需要我們捕捉可能的異常(例如,yield 只能返回?個(gè)值,否則會(huì)導(dǎo)致異常 RuntimeError),所以 try...except 語(yǔ)句不能忽略。
感謝各位的閱讀,以上就是“Python初學(xué)者必備的文件讀寫(xiě)方法”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)Python初學(xué)者必備的文件讀寫(xiě)方法這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。