第五章:文件和I/O

任何程序都需要處理輸入和輸出。本章節(jié)介紹了處理各種不同類型文件時的慣用方法,包括文本和二進(jìn)制人間的處理七兜,文件的編碼以及其他的一些相關(guān)內(nèi)容。

1.讀寫文本數(shù)據(jù)

>>>with open ('somefile.txt','rt') as f:
>>>    data = f.read()
>>>#Write chunks of text data
>>>with open('somefile.txt','wt') as f:
>>>    f.write(text1)
>>>    f.write(text2)

類似地福扬,要對文本文件執(zhí)行寫入操作腕铸,可以使用open()函數(shù)的wt模式來完成,如果待操作的文件已經(jīng)存在铛碑,那么這回清除并覆蓋其原先的內(nèi)容狠裹;

如果要在已存在的文件的結(jié)尾處追加內(nèi)容,可以使用open()函數(shù)的at模式汽烦;

  • 一般來說涛菠,讀寫文本文件都是非常簡單直接的,但是撇吞,這里了還是有幾個微妙的細(xì)節(jié)需要引起注意俗冻;首先,我們在實(shí)例中采用了with語句牍颈,這會為使用的文件創(chuàng)建一個上下文環(huán)境迄薄,當(dāng)程序的控制流離開with語快后,文件將會自動關(guān)閉煮岁;我們并不一定要用with語句噪奄,但是如果我們不用的話請確保要記得手動關(guān)閉文件;
>>>f = open('somefile.txt','rt')
>>>data = f.read()
>>>f.close()
  • 關(guān)于默認(rèn)換行符人乓,open()函數(shù)提供了一個newline=''的參數(shù)勤篮;
    with open('somefile.txt','rt',newline = '') as f:

  • 關(guān)于文本文件中可能出現(xiàn)的編碼錯誤,當(dāng)encoding = 'utf-8';
    UnicodeDecodeError:'ascii' codec can't decode byte 0xc3 in position
    如果遇到這樣的錯誤色罚,這通常表示沒有一正確的編碼方式來讀取文件碰缔。可以使用encoding來制定不同的編碼方式戳护;如果還不能避免的話金抡,則可以為open()函數(shù)提供一個可選的errors參數(shù)來慘厲錯誤瀑焦;

>>>#Replace bad chars with Unicode U+fffd replacement char
>>>f = open(somefile.txt','rt',encoding = 'ascii',errors = 'replace')
>>>f.read()
'Spicy Jalape?o'
>>>#Replace bad chars entirely
>>>f = open(somefile.txt','rt',encoding = 'ascii',errors = 'ignore')
>>>f.read()
'Spicy Jalapeo'

如果常常在擺弄open()函數(shù)的encoding和errors參數(shù),并為此做了大量的技巧性操作梗肝,那就適得其反了榛瓮;因?yàn)樯畋静粦?yīng)該如此艱難,關(guān)于文本巫击,第一條守則就是只需要確辟飨總是使用正確的文本編碼形式即可;請使用默認(rèn)的編碼設(shè)定(通常utf-8)

2.將輸出重定向到文件中

問題:我們想把print()函數(shù)的輸出重定向到一個文件中坝锰。

解決方案:我們只需要在print()函數(shù)加上file關(guān)鍵字參數(shù)即可粹懒;

>>>with open('somefile.txt','rt') as f:
>>>    print("hello world!",f)

3.以不同的分隔符或行結(jié)尾完成打印

問題:我們想通過print()函數(shù)輸出數(shù)據(jù),但是同時也希望修改分隔符或者行結(jié)尾符

解決方案:可以在print()函數(shù)中使用sep和end關(guān)鍵字參數(shù)來根據(jù)需要修改輸出顷级;

>>> print('ACME',50,90.4)
ACME 50 90.4
>>> print('ACME',50,90.4,sep=',')
ACME,50,90.4
>>> print('ACME',50,90.4,sep=',',end='!!\n')
ACME,50,90.4!!

我們可以使用end參數(shù)在輸出中禁止打印出換行符的方式:

>>> for i in range(5):
...     print(i)
...
0
1
2
3
4
>>> for i in range(5):
...     print(i,end=' ')
...
0 1 2 3 4 >>>

str.join 問題也可以處理簡單的字符分隔文本問題凫乖;

>>> row = ('ACME',50,91.5)
>>> print(','.join(row))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: sequence item 1: expected str instance, int found
>>> print(','.join(str(w) for w in row))
ACME,50,91.5

更加高效的方法:

>>> print(*row,sep = ',')
ACME,50,91.5

4.對鞋二進(jìn)制數(shù)據(jù)

解決方案:使用open()函數(shù)的rb模式或者wb模式就可以實(shí)現(xiàn)對二進(jìn)制數(shù)據(jù)的讀或者寫;

5.對已不存在的文件執(zhí)行寫入操作

問題:我們想將數(shù)據(jù)寫入到一個文件中弓颈,但只當(dāng)該文件已經(jīng)不在文件系統(tǒng)中時才這么做帽芽;

解決方案:這個問題可以通過使用open()函數(shù)中鮮為人知的x模式替換常見的w模式來解決

>>> with open('d:\\tmp.txt','wt') as f:
...     f.write("Hello\n")
...
6
>>> with open('d:\\tmp.txt','xt') as f:
...     f.write("Hello\n")
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
FileExistsError: [Errno 17] File exists: 'd:\\tmp.txt'

如果文件時二進(jìn)制模式,那么用xb替代xt即可翔冀;

6.在字符串上執(zhí)行I/O操作

7.讀寫壓縮的數(shù)據(jù)文件

問題:我們需要讀寫以gzip嚣镜、bz2格式壓縮的文件中的數(shù)據(jù):

解決方案:gzip、bz2,模塊使得同這類壓縮型文件打交道變得非常簡單橘蜜,這兩個模塊都提供了open()的其他實(shí)現(xiàn)菊匿,可用于處理壓縮文件;

#gzip compression
>>>import gzip
>>>with gzip.open('somefile.gz','rt') as f:
>>>    text = f.read()

#bz2 compression
>>>import bz2
>>>with bz2.open('somefile.bz2','rt') as f:
>>>    text = f.read()

對應(yīng)的寫入文件也相似计福;
大部分情況下讀寫壓縮數(shù)據(jù)都是簡單而直接的跌捆,單請注意,選擇正確的文件模式是至關(guān)重要的象颖。如果沒有指定的模式佩厚,那么默認(rèn)的模式是二進(jìn)制,這會使得期望接受文本的程序奔潰说订。gzip.open()和bz2.open()所接受的參數(shù)和內(nèi)建的open()函數(shù)一樣抄瓦,也支持encoding,newline陶冷,errors等關(guān)鍵字參數(shù)钙姊;
當(dāng)寫入壓縮數(shù)據(jù)時,壓縮級別可以通過compresslevel關(guān)鍵字參數(shù)來指定埂伦,這是可選的煞额;

>>>with gzip.open('somefile.gz','wt',compresslevel = 5) as f:
>>>    f.write(text)

默認(rèn)級別是9,代表著最高的壓縮等級。低等級的壓縮可帶來更好的性能表現(xiàn)膊毁,但壓縮比就沒那么大胀莹;

8.對固定大小的記錄進(jìn)行迭代

9.將二進(jìn)制數(shù)據(jù)兌取到可變緩沖區(qū)中

10.對二進(jìn)制文件做內(nèi)存映射

11.處理路徑名

問題:我們需要處理路徑名以找出基文件名,目錄名婚温,絕對路徑等相關(guān)信息描焰;

解決方案:要操作路徑名,可以使用os.path模塊中的函數(shù)

>>> import os
>>> path = "D:\ostext\meizitu\mzt01\\10a33.jpg"
>>> os.path.basename(path)
'10a33.jpg'
>>> os.path.dirname(path)
'D:\\ostext\\meizitu\\mzt01'
>>> os.path.join('tmp','data',os.path.basename(path))
'tmp\\data\\10a33.jpg'
>>> os.path.expanduser(path)
'D:\\ostext\\meizitu\\mzt01\\10a33.jpg'
#分離擴(kuò)展名
>>> os.path.splitext(path)
('D:\\ostext\\meizitu\\mzt01\\10a33', '.jpg')

一栅螟、python中對文件荆秦、文件夾操作時經(jīng)常用到的os模塊和shutil模塊常用方法。
1.得到當(dāng)前工作目錄嵌巷,即當(dāng)前Python腳本工作的目錄路徑: os.getcwd()
2.返回指定目錄下的所有文件和目錄名:os.listdir()
3.函數(shù)用來刪除一個文件:os.remove()
4.刪除多個目錄:os.removedirs(r“c:\python”)
5.檢驗(yàn)給出的路徑是否是一個文件:os.path.isfile()
6.檢驗(yàn)給出的路徑是否是一個目錄:os.path.isdir()
7.判斷是否是絕對路徑:os.path.isabs()
8.檢驗(yàn)給出的路徑是否真地存:os.path.exists()
9.返回一個路徑的目錄名和文件名:os.path.split() eg os.path.split('/home/swaroop/byte/code/poem.txt') 結(jié)果:('/home/swaroop/byte/code', 'poem.txt')
10.分離擴(kuò)展名:os.path.splitext()
11.獲取路徑名:os.path.dirname()
12.獲取文件名:os.path.basename()
13.運(yùn)行shell命令: os.system()
14.讀取和設(shè)置環(huán)境變量:os.getenv() 與os.putenv()
15.給出當(dāng)前平臺使用的行終止符:os.linesep Windows使用'\r\n',Linux使用'\n'而Mac使用'\r'
16.指示你正在使用的平臺:os.name 對于Windows室抽,它是'nt'搪哪,而對于Linux/Unix用戶,它是'posix'
17.重命名:os.rename(old坪圾, new)
18.創(chuàng)建多級目錄:os.makedirs(r“c:\python\test”)
19.創(chuàng)建單個目錄:os.mkdir(“test”)
20.獲取文件屬性:os.stat(file)
21.修改文件權(quán)限與時間戳:os.chmod(file)
22.終止當(dāng)前進(jìn)程:os.exit()
23.獲取文件大邢邸:os.path.getsize(filename)



glob是python自己帶的一個文件操作相關(guān)模塊,內(nèi)容也不多兽泄,用它可以查找符合自己目的的文件漓概,就類似于Windows下的文件搜索,而且也支持通配符病梢,,?,[]這三個通配符胃珍,代表0個或多個字符,?代表一個字符蜓陌,[]匹配指定范圍內(nèi)的字符觅彰,如[0-9]匹配數(shù)字。

它的主要方法就是glob,該方法返回所有匹配的文件路徑列表钮热,該方法需要一個參數(shù)用來指定匹配的路徑字符串(本字符串可以為絕對路徑也可以為相對路徑)填抬,比如:

#我這里就是獲得C盤下的所有txt文件
>>>import glob
>>>glob.glob(r'c:/*.txt')

#獲得指定目錄下的所有jpg文件
glob.glob(r'E:/pic/*/*.jpg')

iglob方法

獲取一個可編歷對象, 使用它可以逐個獲取匹配的文件路徑名隧期。與glob.glob()的區(qū)別是:glob.glob同時獲取所有的匹配路徑飒责,而 glob.iglob一次只獲取一個匹配路徑。這有點(diǎn)類似于.NET中操作數(shù)據(jù)庫用到的DataSet與DataReader仆潮。下面是一個簡單的例子:

import glob     
#父目錄中的.py文件  
f = glob.iglob(r'../*.py')  


12.檢測文件是否存在

>>>os.path.exists('/etc/passwd')
True
>>>os.path.exists('/etc/spam')
False

#
>>>os.path.isfile('/etc/passwd')
>>>os.path.isdir('/etc/passwd')
>>>os.path.islink('/etc/passwd')
>>>os.path.realpath('/etc/passwd')

#
>>> os.path.getsize(path)
100714
>>> os.path.getmtime(path)
1512957742.67442
>>> import time
>>> time.ctime(os.path.getmtime(path))
'Mon Dec 11 10:02:22 2017'

13.獲取目錄內(nèi)容的內(nèi)部

解決方案:可以使用os.listdir()函數(shù)來獲取目錄中的文件列表宏蛉;

>>>import os
>>>names = os.listdir(path)

字符串的startswith()和endswith()方法對于篩選目錄中的內(nèi)容也同樣有用;
至于文件名的匹配性置¢茉危可以使用glob或者fnmatch()模塊;

>>>import glob
>>>pyfiles = glob.glob('somedir/*.py')
#
>>>from fnmatch import fnmatch
>>>pyfiles = [name for name in os.listdir('somedir')]
>>>    if fnmatch(name,'*.py')

14.繞過文件名編碼

15.打印無法解碼的文件

16.為已經(jīng)打開的文件添加或修改編碼方式

17.將字節(jié)寫入到文本文件

18.將已有的文件描述符包裝為文件對象

19.創(chuàng)建臨時文件和目錄

20.同串口進(jìn)行通信

21.序列化Python對象

問題:我們需要將Python對象序列化為字節(jié)流,這樣就可以保存到文件中辟灰,存儲到數(shù)據(jù)庫中或者通過網(wǎng)絡(luò)連接進(jìn)行傳輸个榕;

解決方案:序列化數(shù)據(jù)最常見的做法就是使用pickle模塊,其中:要將某個對象轉(zhuǎn)存儲到文件中芥喇,可以舒勇pickle.dump();如果要從字節(jié)流中創(chuàng)建出對象西采,可以使用peckle.load()或者pickle.loads()函數(shù);

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末继控,一起剝皮案震驚了整個濱河市械馆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌武通,老刑警劉巖霹崎,帶你破解...
    沈念sama閱讀 221,820評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異冶忱,居然都是意外死亡尾菇,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評論 3 399
  • 文/潘曉璐 我一進(jìn)店門囚枪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來派诬,“玉大人,你說我怎么就攤上這事链沼∧福” “怎么了?”我有些...
    開封第一講書人閱讀 168,324評論 0 360
  • 文/不壞的土叔 我叫張陵括勺,是天一觀的道長缆八。 經(jīng)常有香客問我,道長疾捍,這世上最難降的妖魔是什么耀里? 我笑而不...
    開封第一講書人閱讀 59,714評論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮拾氓,結(jié)果婚禮上冯挎,老公的妹妹穿的比我還像新娘。我一直安慰自己咙鞍,他們只是感情好房官,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著续滋,像睡著了一般翰守。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上疲酌,一...
    開封第一講書人閱讀 52,328評論 1 310
  • 那天蜡峰,我揣著相機(jī)與錄音了袁,去河邊找鬼。 笑死湿颅,一個胖子當(dāng)著我的面吹牛载绿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播油航,決...
    沈念sama閱讀 40,897評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼崭庸,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了谊囚?” 一聲冷哼從身側(cè)響起怕享,我...
    開封第一講書人閱讀 39,804評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎镰踏,沒想到半個月后函筋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,345評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡奠伪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評論 3 340
  • 正文 我和宋清朗相戀三年跌帐,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片芳来。...
    茶點(diǎn)故事閱讀 40,561評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡含末,死狀恐怖猜拾,靈堂內(nèi)的尸體忽然破棺而出即舌,到底是詐尸還是另有隱情,我是刑警寧澤挎袜,帶...
    沈念sama閱讀 36,238評論 5 350
  • 正文 年R本政府宣布顽聂,位于F島的核電站,受9級特大地震影響盯仪,放射性物質(zhì)發(fā)生泄漏紊搪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評論 3 334
  • 文/蒙蒙 一全景、第九天 我趴在偏房一處隱蔽的房頂上張望耀石。 院中可真熱鬧,春花似錦爸黄、人聲如沸滞伟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,417評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽梆奈。三九已至,卻和暖如春称开,著一層夾襖步出監(jiān)牢的瞬間亩钟,已是汗流浹背乓梨。 一陣腳步聲響...
    開封第一講書人閱讀 33,528評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留清酥,地道東北人扶镀。 一個月前我還...
    沈念sama閱讀 48,983評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像总处,于是被迫代替她去往敵國和親狈惫。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評論 2 359

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理鹦马,服務(wù)發(fā)現(xiàn)胧谈,斷路器,智...
    卡卡羅2017閱讀 134,702評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,297評論 25 707
  • linux資料總章2.1 1.0寫的不好抱歉 但是2.0已經(jīng)改了很多 但是錯誤還是無法避免 以后資料會慢慢更新 大...
    數(shù)據(jù)革命閱讀 12,175評論 2 33
  • lumicinta閱讀 321評論 0 0
  • 近兩天ps軍人形象的人老多荸频,可憐孩子菱肖,丑人多作怪不是,p的不像自己就是好看旭从?你得多嫌棄你自己稳强? 爹媽給的就是世界上...
    縱情嬉戲天地間閱讀 273評論 0 0