Python學習筆記(九)文件輸入/輸出

文件輸入/輸出

數(shù)據(jù)持久化最簡單的類型是普通文件粪般,有時也叫平面文件(?at ?le)。它僅僅是在一個文件 名下的字節(jié)流闸拿,把數(shù)據(jù)從一個文件讀入內存空盼,然后從內存寫入文件。Python 很容易實現(xiàn)這 些文件操作新荤,它模仿熟悉的和流行的 Unix 系統(tǒng)的操作揽趾。
讀寫一個文件之前需要打開它:
fileobj = open(filename,mode)
下面時對該open()調用的簡單解釋:

  • fileobj時open()返回的文件對象苛骨。
  • filename是該文件的字符串名
  • mode是指明文件類型和操作的字符串

mode 的第一個字母表示對其的操作篱瞎。

  • r 表示讀模式
  • w 表示寫模式,如果文件不存在則新創(chuàng)建痒芝,如果存在則重寫新內容
  • x 表示文件不存在的情況下新創(chuàng)建并寫入文件
  • a 表示如果文件存在俐筋,在文件末尾追加寫內容

mode 的第二個字母是文件類型1:

  • t (或者省略)代表文本類型
  • b 代表二進制文件

打開文件之后就可以調用函數(shù)來讀寫數(shù)據(jù)。
最后需要關閉文件严衬。

接下來我們會在一個程序中用Python字符串創(chuàng)建一個文件澄者,然后返回。


使用write()寫文本文件

首先創(chuàng)建我們使用的文本源:
In [4]: poem = '''There was a young lady named Bright, 
   ...: Whose speed was far faster than light; 
   ...: She started one day 
   ...: In a relative way, 
   ...: And returned on the previous night.'''

In [5]: len(poem)
Out[5]: 154
將文本源添加到文件'relativity' 中:
In [6]: fout = open('relativity','wt')
In [7]: fout.write(poem)
In [8]: fout.close()

函數(shù)write()返回寫入文件的字節(jié)數(shù)。和print()一樣粱挡,它沒有增加空格或換行符赠幕。同樣,我們也可以在一個文本文件中使用print()询筏。

In [15]: fout = open
In [16]: fout = open('relativity','wt')
In [17]: print(poem,file=fout)
In [18]: fout.close()

這就產生了一個問題:到底是使用 write() 還是 print() 劣坊? print() 默認會在每個參數(shù)后 面添加空格,在每行結束處添加換行屈留。 在之前的例子中局冰,它在文件 relativity 中默認添 加了一個換行。為了使 print() 與 write() 有同樣的輸出灌危,傳入下面兩個參數(shù)康二。

  • sep分隔符:默認是一個空格 ' '
  • end結束字符:默認是一個換行符'\n'

除非自定義參數(shù),否則print()會使用默認參數(shù)勇蝙。在這里沫勿,我們通過空字符串替換print()添加對的所有多余輸出:

In [19]: fout = open('relativity','wt',sep=' ',end=' ')
In [20]: print(poem,file=fout)
In [21]: fout.close()

上面的場景,打開文件就清晰很多味混,在未設置換行時候产雹,最后一行是沒有換行的。

如果源字符串非常大翁锡,可以將數(shù)據(jù)分塊蔓挖,直到所有字符被寫入:

In [19]: fout = open('relativity','wt')
In [20]: size = len(poem)
In [21]: offset = 0 
In [22]: chunk = 100 

In [23]: while True:
    ...:     if offset > size:
    ...:         break
    ...:     fout.write(poem[offset:offset+chunk])
    ...:     offset += chunk
    ...:      
In [24]: fout.close()

第一次寫入100個字符,然后寫入剩下的50個字符馆衔。
如果文件 'relativity' 已經存在瘟判,使用模式 x 可以避免重寫文件:

In [25]: fout = open('relativity','xt')
Traceback (most recent call last):   File "<stdin>", line 1, in <module> FileExistsError: [Errno 17] File exists: 'relativity'

可以添加一個異常處理:

In [27]: try:
    ...:     fout = open('relativity', 'xt')
    ...:     fout.write('stomp stomp stomp') 
    ...: except:
    ...:     print('relativity already exists!. That was a close one.') 
    ...:      
relativity already exists!. That was a close one.

使用read(),readline()或者readlines()讀文本文件

我們可以使用不帶參數(shù)的read()函數(shù)一次讀入文件的所有內容角溃。

In [17]: fin = open('relativity','rt')
In [18]: poem = fin.read()
In [19]: fin.close()

同樣也可以設置最大的讀入字符數(shù)限制 read() 函數(shù)一次返回的大小拷获。下面一次讀入 100 個 字符,然后把每一塊拼接成原來的字符串 poem:

In [40]: fin = open('relativity','rt')
In [41]: while True:
    ...:     fragment = fin.read(chunk)
    ...:     if not fragment:
    ...:         break
    ...:     poem += fragment 
    ...:      
In [42]: fin.close()

讀到文件結尾之后减细,再次調用 read() 會返回空字符串('')匆瓜,if not fragment 條件被判為 False。此時會跳出 while True 的循環(huán)未蝌。 當然驮吱,我們也能使用 readline() 每次讀入文件的一 行。在下面栗子中树埠,通過追加每一行拼接成原來的字符串 poem:

In [5]: poem = '' 
In [6]: fin = open('relativity','rt')
In [7]: while True:
   ...:     line = fin.readline()
   ...:     if not line:
   ...:         break
   ...:     poem += line
   ...:      
In [8]: fin.close()

對于一個文本文件糠馆,即使空行也有1字符長度(換行字符 '\n')嘶伟,自然就會返回True怎憋。當 文件讀取結束后,readline()(類似 read())同樣會返回空字符串,也被 while True 判 為 False绊袋。

In [9]: poem = ''
In [10]: fin = open('relativity','rt')
In [11]: for line in fin:
    ...:     poem += line 
    ...:      
In [12]: fin.close()

前面所有的栗子最終都返回單個字符串poem毕匀。函數(shù)readlines()調用時每次讀取一行,并且返回單行字符串的列表:

In [19]: fin = open('relativity','rt')
In [20]: lines = fin.readlines()
In [21]: print(len(lines),'lines read')
5 lines read
In [22]: for line in lines:
    ...:     print(line,end='')
    ...:

使用write()寫二進制文件

如果文件模式字符串中包含'b'癌别,那么文件會以二進制模式打開皂岔。這種情況下,讀寫的是字節(jié)而不是字符串展姐。

我們首先生成一串二進制數(shù)據(jù):
In [25]: bdata = bytes(range(0,256))
In [26]: len(bdata)
Out[26]: 256
以二進制模式打開躁垛,并且一次寫入所有的數(shù)據(jù):
In [27]: fout = open('bfile','wb')
In [28]: fout.write(bdata)
Out[28]: 256
write()返回寫入的字節(jié)數(shù)
In [29]: fout.close()

對于文本文件,也可以分塊寫二進制數(shù)據(jù)圾笨。

In [30]: fout = open('bfile','wb')
In [31]: size = len(bdata)
In [32]: chunk = 100 
In [33]: offset = 0
In [34]: while True: 
    ...:     if offset > size:
    ...:         break
    ...:     fout.write(bdata[offset:offset+chunk])
    ...:     offset += chunk 
    ...:  
In [35]: fout.close()

使用read()讀取二進制文件

下面的栗子只需要用'rb'打開文件即可:

In [38]: fin = open('bfile','rb')
In [39]: bdata = fin.read()
In [40]: len(bdata)
Out[40]: 256

In [41]: fin.close()

使用with自動關閉文件

如果你忘記關閉已經打開的一個文件教馆, 在該文件對象不再被引用之后 Python 會關掉此文 件。這也就意味著在一個函數(shù)中打開文件擂达,沒有及時關閉它土铺,但是在函數(shù)結束時會被關 掉。然而你可能會在一直運行中的函數(shù)或者程序的主要部分打開一個文件板鬓,應該強制剩下 的所有寫操作完成后再關閉文件悲敷。
Python的上下文管理器(context manager)會清理一些資源,例如打開的文件俭令。它的形式為 with expression as variable:

In [42]: with open('withfile','wt') as fout: 
    ...:     fout.write(poem)
    ...:      

完成上下文管理器的代碼后后德,文件會自動關閉


使用seek()改變位置

無論是讀或者寫文件,Python都會跟蹤文件中的位置抄腔。函數(shù)tell()返回距離文件開始處的字節(jié)偏移量探遵。函數(shù)seek()允許跳轉到其他字節(jié)偏移量的位置。這意味著可以不用從頭讀取文件的每一個字節(jié)妓柜,直接跳轉到最后位置并只讀一個字節(jié)也是可以的箱季。
下面就是我們的栗子:

使用之前的二進制文件bfile
In [43]: fin = open('bfile','rb')
In [44]: fin.tell()
Out[44]: 0
使用 seek() 讀取文件結束前最后一個字節(jié):
In [45]: fin.seek(255)
Out[45]: 255
一直讀到文件結束:
In [46]: bdata = fin.read()
In [47]: len(bdata)
Out[47]: 1

In [48]: bdata[0]
Out[48]: 255

調用seek()函數(shù)的時候,可以使用兩個參數(shù):seek(offset,origin)棍掐。

  • 如果origin等于(默認為0)藏雏,從開頭便宜offset個字節(jié)
  • 如果origin等于1,從當前位置偏移offset個字節(jié)
  • 如果origin等于2作煌,距離最后結束處偏移offset個字節(jié)

這些值也在標準os模塊中被定義:

In [1]: import os 
In [2]: os.SEEK_SET
Out[2]: 0

In [3]: os.SEEK_CUR
Out[3]: 1

In [4]: os.SEEK_END
Out[4]: 2

我們可以用不同的方法讀取最后一個字節(jié):

In [9]: fin = open('bfile','rb')
結尾前的一個字節(jié):
In [10]: fin.seek(-1,2)
Out[10]: 255

In [11]: fin.tell()
Out[11]: 255
在調用seek()函數(shù)時不需要額外調用tell()掘殴。上面只是說明兩個函數(shù)具有相同的偏移量
一直讀到結尾:
In [12]: bdata = fin.read()
In [13]: len(bdata)
Out[13]: 1

In [14]: bdata[0]
Out[14]: 255

下面時從文件的當前位置尋找的栗子:

In [15]: fin = open('bfile','rb')
下面的栗子返回最后兩個字節(jié):
In [16]: fin.seek(254,0)
Out[16]: 254

In [17]: fin.tell()
Out[17]: 254

在此基礎上前進一個字節(jié):

In [18]: fin.seek(1,1)
Out[18]: 255

In [19]: fin.tell()
Out[19]: 255
最后一直讀到文件結尾:
In [20]: bdata = fin.read()
In [21]: len(bdata)
Out[21]: 1

In [22]: bdata[0]
Out[22]: 255

這些函數(shù)對于二進制文件都是極其重要的。當文件是 ASCII 編碼(每個字符一個字節(jié)) 時粟誓,也可以使用它們奏寨,但是計算偏移量會是一件麻煩事。其實鹰服,這些都取決于文本的編碼 格式病瞳,最流行的編碼格式(例如 UTF-8)每個字符的字節(jié)數(shù)都不盡相同揽咕。

注:本文內容來自《Python語言及其應用》歡迎購買原書閱讀

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市套菜,隨后出現(xiàn)的幾起案子亲善,更是在濱河造成了極大的恐慌,老刑警劉巖逗柴,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蛹头,死亡現(xiàn)場離奇詭異,居然都是意外死亡戏溺,警方通過查閱死者的電腦和手機渣蜗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來旷祸,“玉大人袍睡,你說我怎么就攤上這事±呱” “怎么了斑胜?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長嫌吠。 經常有香客問我止潘,道長,這世上最難降的妖魔是什么辫诅? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任凭戴,我火速辦了婚禮,結果婚禮上炕矮,老公的妹妹穿的比我還像新娘么夫。我一直安慰自己,他們只是感情好肤视,可當我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布档痪。 她就那樣靜靜地躺著,像睡著了一般邢滑。 火紅的嫁衣襯著肌膚如雪腐螟。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天困后,我揣著相機與錄音乐纸,去河邊找鬼。 笑死摇予,一個胖子當著我的面吹牛汽绢,可吹牛的內容都是我干的。 我是一名探鬼主播侧戴,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼宁昭,長吁一口氣:“原來是場噩夢啊……” “哼跌宛!你這毒婦竟也來了?” 一聲冷哼從身側響起久窟,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎本缠,沒想到半個月后斥扛,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡丹锹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年稀颁,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片楣黍。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡匾灶,死狀恐怖,靈堂內的尸體忽然破棺而出租漂,到底是詐尸還是另有隱情阶女,我是刑警寧澤,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布哩治,位于F島的核電站秃踩,受9級特大地震影響,放射性物質發(fā)生泄漏业筏。R本人自食惡果不足惜憔杨,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蒜胖。 院中可真熱鬧消别,春花似錦、人聲如沸台谢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽朋沮。三九已至荆虱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間朽们,已是汗流浹背怀读。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留骑脱,地道東北人菜枷。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像叁丧,于是被迫代替她去往敵國和親啤誊。 傳聞我的和親對象是個殘疾皇子岳瞭,可洞房花燭夜當晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內容

  • PHP常用函數(shù)大全 usleep() 函數(shù)延遲代碼執(zhí)行若干微秒。 unpack() 函數(shù)從二進制字符串對數(shù)據(jù)進行解...
    上街買菜丶迷倒老太閱讀 1,366評論 0 20
  • php usleep() 函數(shù)延遲代碼執(zhí)行若干微秒蚊锹。 unpack() 函數(shù)從二進制字符串對數(shù)據(jù)進行解包瞳筏。 uni...
    思夢PHP閱讀 1,984評論 1 24
  • 在宿舍呆了一天,感覺甚是無聊牡昆。拿上幾本書姚炕,準備去教室自習,今天出乎意料的冷丢烘,小風一陣陣的柱宦,此時我突然想起了昨天給家...
    啦啦啦的哥欠閱讀 211評論 0 1
  • 這個氣候和溫度,是南京的秋天吧播瞳〉Э口舌干燥,喉嚨癢痛赢乓,這種感覺已然持續(xù)幾日了忧侧, 干燥的風吹得人臉上有輕微的割痛感,吹...
    軟語華閱讀 181評論 0 0
  • 《The end of love》 goodbye my love 再見牌芋,我的愛人 you have been t...
    may徊閱讀 204評論 0 0