Python 簡明教程 --- 24,Python 文件讀寫

過去的代碼都是未經(jīng)測試的代碼渴频。

目錄

無論是哪種編程語言芽丹,IO 操作都是非常重要的部分。IInput(輸入)卜朗,OOutput(輸出)拔第。

IO 操作一般分為以下兩種:

  • 磁盤IO: 即在磁盤上讀寫文件。讀文件是指將文件內(nèi)容從磁盤讀入內(nèi)存场钉,寫文件是指將內(nèi)存中的內(nèi)容寫到磁盤蚊俺。
  • 網(wǎng)絡(luò)IO: 即文件在網(wǎng)絡(luò)上傳輸。網(wǎng)絡(luò)傳輸一般會有兩種角色逛万,分別是服務(wù)端(如HTTP Server)和客戶端(如瀏覽器)泳猬。

本節(jié)我們主要介紹磁盤IO,即文件讀寫泣港。

1暂殖,open 函數(shù)介紹

要想讀寫文件价匠,首先要打開一個(gè)文件当纱。

Python 中的內(nèi)建函數(shù)open 用來打開一個(gè)文件,我們可以使用help(open)踩窖,來查看open 函數(shù)的原型坡氯,如下:

open(file, mode='r', 
    buffering=-1, encoding=None,
    errors=None, newline=None, 
    closefd=True, opener=None)

該函數(shù)成功調(diào)用時(shí)會返回一個(gè)流stream,用于讀寫文件等操作洋腮;發(fā)生錯誤時(shí)會拋出IOError 異常箫柳。

被打開的文件占用了系統(tǒng)資源,使用完后要記得close啥供,否則會浪費(fèi)系統(tǒng)資源悯恍。

不管以讀模式打開文件,還是以寫模式打開文件伙狐,成功打開一個(gè)文件后涮毫,這個(gè)可操作文件的的內(nèi)部都有一個(gè)隱含的指針,一般這個(gè)指針會指向文件開頭或者文件末尾的位置贷屎,表示從文件的哪個(gè)位置讀寫文件罢防。

可以看到,該函數(shù)支持8 個(gè)參數(shù)唉侄,但最重要的是前兩個(gè)參數(shù):

  • file:是指要打開的文件的路徑
  • mode:是指以什么模式打開文件咒吐,要用引號引住

mode 參數(shù)支持的模式(默認(rèn)為讀文本模式,即rt)如下:

  • r:以讀模式打開文件(默認(rèn)方式),指針在文件開頭
  • w:以寫模式打開文件恬叹,如果件已存在候生,則內(nèi)容會被清空(指針在文件開頭);如果文件不存在绽昼,則會創(chuàng)建新文件
  • x:創(chuàng)建一個(gè)新文件陶舞,并以寫模式打開,指針在文件開頭绪励,如果文件已存在肿孵,則拋出FileExistsError異常
  • a:以寫模式打開文件,如果文件已有內(nèi)容疏魏,在寫入內(nèi)容時(shí)停做,會追加到文件末尾(指針在文件末尾)
  • b:以二進(jìn)制模式打開文件,一般用于讀寫二進(jìn)制文件大莫,如圖片蛉腌,視頻等
  • t:以文本模式打開文件(默認(rèn)方式),一般用于讀寫文本文件
  • +:以讀寫模式打開文件只厘,指針在文件開頭

這些模式還可以組合使用烙丛,常見的組合如下:

  • rb:以二進(jìn)制模式打開一個(gè)文件,用于只讀
  • r+:打開一個(gè)文件羔味,用于讀寫
  • rb+:以二進(jìn)制模式打開一個(gè)文件河咽,用于讀寫
  • wb:以二進(jìn)制模式打開一個(gè)文件,用于
  • w+:打開一個(gè)文件赋元,用于讀寫
  • wb+: 以二進(jìn)制模式打開一個(gè)文件忘蟹,用于讀寫
  • ab: 以二進(jìn)制模式打開一個(gè)文件,用于追加
  • a+:打開一個(gè)文件用于讀寫搁凸,指針在文件末尾
  • ab+:以二進(jìn)制模式打開一個(gè)文件媚值,用于讀寫,指針在文件末尾

2护糖,open 函數(shù)示例

如下代碼褥芒,成功打開文件./1.txt

f = open('./1.txt')

通過type(f)查看open 函數(shù)的返回值的類型:

>>> type(file)
<class '_io.TextIOWrapper'>

可看到,其返回值類型為_io.TextIOWrapper嫡良。

我們用dir(f) 來查看對象 f 支持的屬性和方法:

>>> dir(file)
['_CHUNK_SIZE', '__class__', '__del__', '__delattr__', '__dict__', 
'__dir__', '__doc__', '__enter__', '__eq__', '__exit__', '__format__', 
'__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', 
'__init__', '__init_subclass__', '__iter__', '__le__', '__lt__', 
'__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', 
'__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 
'_checkClosed', '_checkReadable', '_checkSeekable', '_checkWritable', 
'_finalizing', 
'buffer', 'close', 'closed', 'detach', 'encoding', 'errors', 'fileno', 
'flush', 'isatty', 'line_buffering', 'mode', 'name', 'newlines', 'read', 
'readable', 'readline', 'readlines', 'seek', 'seekable', 'tell', 
'truncate', 'writable', 'write', 'writelines']

可以通過help(f.方法名) 來查看每個(gè)方法的幫助手冊锰扶,也可以使用help(f) 來查看該對象的所有屬性和方法,及其簡介皆刺。

我們來看一下常用方法的作用:

  • mode:打開文件時(shí)的模式
  • name:被打開的文件名
  • close:關(guān)閉文件流少辣,并刷新緩沖區(qū)中的內(nèi)容,之后不能再操作文件
  • closed:文件流是否已關(guān)閉
  • flush:刷新寫緩沖區(qū)羡蛾,只寫流非阻塞流不適用
  • read:讀入文件內(nèi)容
  • readable:是否可讀
  • readline:讀入一行內(nèi)容
  • readlines:讀入文件所有的行漓帅,直至文件末尾
  • seek:移動文件指針的位置
  • seekable:文件指針是否可被移動
  • tell:返回文件指針當(dāng)前位置
  • truncate:截?cái)辔募?nèi)容
  • writable:是否可寫
  • write:向文件中寫入內(nèi)容
  • writelines:向文件中寫入多行

3,關(guān)閉系統(tǒng)資源

正確的調(diào)用close() 函數(shù)是關(guān)鍵的。

在成功打開一個(gè)文件后忙干,對該文件進(jìn)行操作(讀寫)時(shí)器予,有可能發(fā)生異常。

比如我們打開的文件只能用來捐迫,如果用來乾翔,則會發(fā)生異常:

>>> f = open('1.txt', 'w')  # 用只讀模式打開文件
>>> f.readable()            # 查看文件是否可讀
False                       # 返回 False,表示不可讀
>>> f.read()                # 讀文件施戴,發(fā)生異常
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
io.UnsupportedOperation: not readable

如果反浓,我們將這段代碼寫在文件中:

#! /usr/bin/env python3

f = open('1.txt', 'w')
f.read()
f.close()

python3 來執(zhí)行,結(jié)果如下:

$ python3 Test.py 
Traceback (most recent call last):
  File "Test.py", line 4, in <module>
    f.read()
io.UnsupportedOperation: not readable

可以看到赞哗,在執(zhí)行到f.read() 這句代碼的時(shí)候雷则,程序異常退出,那么后邊的f.close() 就沒有執(zhí)行到肪笋,這就導(dǎo)致程序執(zhí)行不夠完整月劈,系統(tǒng)資源沒有關(guān)閉。

這時(shí)藤乙,我們可以用try...finally來處理猜揪,如下:

#! /usr/bin/env python3

f = open('1.txt', 'w')

try:
    f.read()

except Exception as e:
    print('read file err:%s' % e)

finally:
    f.close()
    print('file closed')

上面代碼的執(zhí)行結(jié)果如下:

$ python3 Test.py 
read file err:not readable
file closed

我們將f.close() 這句代碼放在了finally 代碼塊中,這樣坛梁,不管遇到什么情況而姐,f.close() 這句話總會被執(zhí)行,就不會導(dǎo)致系統(tǒng)資源泄漏的問題罚勾。

4毅人,with 語句使用

為了確保系統(tǒng)資源能夠關(guān)閉,Python 中提供了with 語句尖殃,能夠讓我們更加安全方面的使用open 函數(shù),而不用關(guān)心資源關(guān)閉的問題划煮。

with 語句也叫上下文管理器送丰,有了with 語句,我們可以這樣使用open 函數(shù):

with open('./1.txt') as f:
    print(f.read())

這樣的代碼弛秋,不管在with 語句塊內(nèi)出現(xiàn)怎樣的異常器躏,close 函數(shù)都會被調(diào)用,而我們也不需要自己調(diào)用蟹略。

使用with 語句登失,就不再需要使用try...finally 語句,也使得代碼更加簡潔挖炬。

需要特別注意的是揽浙,這里的f只能在with 語句塊中使用,一旦離開with 語句塊,f 就被關(guān)閉了馅巷。如果在with 語句塊之外使用f 進(jìn)行讀寫等操作膛虫,將出現(xiàn)異常。

如下代碼中钓猬,f.closed 將返回True

with open('./1.txt') as f:
    pass
f.closed  # True

5稍刀,with 語句原理

為什么open 函數(shù)能夠使用with 語句?

實(shí)際上open 函數(shù)能夠使用with 語句的原因取決于open 的返回值的類型敞曹。我們知道账月,open 的返回值的類型為_io.TextIOWrapper,而這個(gè)類中有兩個(gè)方法澳迫,__enter__ 方法和__exit__ 方法捶障。

我們再來看下with 語句的格式:

with ... as ... :
    pass

with 關(guān)鍵字的后邊是一個(gè)表達(dá)式as 后邊是一個(gè)變量名纲刀,表達(dá)式的計(jì)算結(jié)果會賦值給as 后邊的變量项炼。

Python 規(guī)定,只要一個(gè)類中有__enter____exit__ 方法示绊,就可以使用with 語句锭部。with 語句后邊的表達(dá)式執(zhí)行完畢后,就會執(zhí)行__enter__ 方法面褐,在退出with 語句塊時(shí)拌禾,會執(zhí)行__exit__ 方法。

我們自己編寫一個(gè)測試類展哭,使其能夠使用with 語句:

#! /usr/bin/env python3

class TestWith:

    def __init__(self):
        print('執(zhí)行__init__')

    def __enter__(self):
        print('執(zhí)行__enter__')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('執(zhí)行__exit__')

        print('exc_type is %s' % exc_type)
        print('exc_val is %s' % exc_val)
        print('exc_tb is %s' % exc_tb)

再該類中有三個(gè)函數(shù):

  • __init__:構(gòu)造函數(shù)湃窍,創(chuàng)建類的對象時(shí)調(diào)用
  • __enter__:進(jìn)入with 語句塊時(shí)會調(diào)用
  • __exit__:離開with 語句塊時(shí)會調(diào)用

其中__exit__ 方法有三個(gè)參數(shù):

  • exc_typewith 語句塊中的代碼發(fā)生異常時(shí)的異常類型
  • exc_val:發(fā)生異常時(shí)的異常值
  • exc_tb:發(fā)生異常時(shí)的traceback 類的對象

我們這樣使用這個(gè)類:

with TestWith() as t:
    print('test with')

python3 來執(zhí)行,結(jié)果如下:

$ python3 Test.py 
執(zhí)行__init__
執(zhí)行__enter__
test with
執(zhí)行__exit__
exc_type is None
exc_val is None
exc_tb is None

可以看到執(zhí)行步驟是這樣的:

  1. 生成該類的對象匪傍,執(zhí)行__init__ 方法
  2. 進(jìn)入with 語句塊您市,執(zhí)行__enter__ 方法
  3. 執(zhí)行with 語句塊中的代碼
  4. 退出with 語句塊,執(zhí)行__exit__ 方法

因?yàn)?code>with 語句塊中沒有發(fā)生異常役衡,所以__exit__ 方法中的 exc_type茵休,exc_valexc_tb 三個(gè)參數(shù)均為None手蝎。

下面再示范一個(gè)with 語句塊中出現(xiàn)異常的代碼:

with TestWith() as t:
    print('test with1...')
    1 / 0   # 除數(shù)為 0榕莺,拋出異常
    print('test with2...')

該代碼的執(zhí)行結(jié)果如下:

$ python3 Test.py 
執(zhí)行__init__
執(zhí)行__enter__
test with1...
執(zhí)行__exit__
exc_type is <class 'ZeroDivisionError'>
exc_val is division by zero
exc_tb is <traceback object at 0x7fe8b7c98888>
Traceback (most recent call last):
  File "Test.py", line 27, in <module>
    1 / 0
ZeroDivisionError: division by zero

通過上面的執(zhí)行結(jié)果可以看到,在執(zhí)行1 / 0 之前棵介,我們不用多說钉鸯。在執(zhí)行到1 / 0 時(shí),出現(xiàn)異常邮辽,然后會執(zhí)行__exit__ 方法唠雕。

在執(zhí)行結(jié)果中贸营,我們能看到 exc_typeexc_val及塘,exc_tb 三個(gè)參數(shù)的值莽使,最后拋出Traceback 異常。

with 語句中笙僚,拋出異常的語句1 / 0 之后的代碼不會再執(zhí)行芳肌。

(完。)


推薦閱讀:

Python 簡明教程 ---19肋层,Python 類與對象
Python 簡明教程 ---20亿笤,Python 類中的屬性與方法
Python 簡明教程 ---21,Python 繼承與多態(tài)
Python 簡明教程 ---22栋猖,Python 閉包與裝飾器
Python 簡明教程 ---23净薛,Python 異常處理

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蒲拉,隨后出現(xiàn)的幾起案子暖哨,更是在濱河造成了極大的恐慌宣吱,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異躺苦,居然都是意外死亡超陆,警方通過查閱死者的電腦和手機(jī)儒恋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進(jìn)店門湖笨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人灵寺,你說我怎么就攤上這事曼库。” “怎么了略板?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵毁枯,是天一觀的道長。 經(jīng)常有香客問我蚯根,道長后众,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任颅拦,我火速辦了婚禮,結(jié)果婚禮上教藻,老公的妹妹穿的比我還像新娘距帅。我一直安慰自己,他們只是感情好括堤,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布碌秸。 她就那樣靜靜地躺著绍移,像睡著了一般。 火紅的嫁衣襯著肌膚如雪讥电。 梳的紋絲不亂的頭發(fā)上蹂窖,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機(jī)與錄音恩敌,去河邊找鬼瞬测。 笑死,一個(gè)胖子當(dāng)著我的面吹牛纠炮,可吹牛的內(nèi)容都是我干的月趟。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼恢口,長吁一口氣:“原來是場噩夢啊……” “哼孝宗!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起耕肩,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤因妇,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后猿诸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體婚被,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年两芳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了摔寨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,040評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡怖辆,死狀恐怖是复,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情竖螃,我是刑警寧澤淑廊,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站特咆,受9級特大地震影響季惩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜腻格,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一画拾、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧菜职,春花似錦青抛、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽适室。三九已至,卻和暖如春举瑰,著一層夾襖步出監(jiān)牢的瞬間捣辆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工此迅, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留汽畴,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓邮屁,卻偏偏與公主長得像整袁,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子佑吝,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容