python文件處理

一 引入

應(yīng)用程序運行過程中產(chǎn)生的數(shù)據(jù)最先都是存放于內(nèi)存中的,若想永久保存下來,必須要保存于硬盤中蛇损。應(yīng)用程序若想操作硬件必須通過操作系統(tǒng),而文件就是操作系統(tǒng)提供給應(yīng)用程序來操作硬盤的虛擬概念钳榨,用戶或應(yīng)用程序?qū)ξ募牟僮鳎褪窍虿僮飨到y(tǒng)發(fā)起調(diào)用纽门,然后由操作系統(tǒng)完成對硬盤的具體操作。

二 文件操作的基本流程

2.1 基本流程

有了文件的概念营罢,我們無需再去考慮操作硬盤的細(xì)節(jié)赏陵,只需要關(guān)注操作文件的流程:

# 1. 打開文件,由應(yīng)用程序向操作系統(tǒng)發(fā)起系統(tǒng)調(diào)用open(...)饲漾,操作系統(tǒng)打開該文件蝙搔,對應(yīng)一塊硬盤空間,并返回一個文件對象賦值給一個變量ff=open('a.txt','r',encoding='utf-8')#默認(rèn)打開模式就為r

# 2. 調(diào)用文件對象下的讀/寫方法考传,會被操作系統(tǒng)轉(zhuǎn)換為讀/寫硬盤的操作data=f.read()

# 3. 向操作系統(tǒng)發(fā)起關(guān)閉文件的請求吃型,回收系統(tǒng)資源f.close()


2.2 資源回收與with上下文管理

打開一個文件包含兩部分資源:應(yīng)用程序的變量f和操作系統(tǒng)打開的文件。在操作完畢一個文件時僚楞,必須把與該文件的這兩部分資源全部回收勤晚,回收方法為:

1、f.close()#回收操作系統(tǒng)打開的文件資源

2泉褐、delf#回收應(yīng)用程序級的變量

其中del f一定要發(fā)生在f.close()之后赐写,否則就會導(dǎo)致操作系統(tǒng)打開的文件無法關(guān)閉,白白占用資源膜赃, 而python自動的垃圾回收機(jī)制決定了我們無需考慮del f挺邀,這就要求我們,在操作完畢文件后,一定要記住f.close()端铛,雖然我們?nèi)绱藦?qiáng)調(diào)泣矛,但是大多數(shù)讀者還是會不由自主地忘記f.close(),考慮到這一點禾蚕,python提供了with關(guān)鍵字來幫我們管理上下文

# 1乳蓄、在執(zhí)行完子代碼塊后,with 會自動執(zhí)行f.close() with open('a.txt','w') as f:

pass

# 2夕膀、可用用with同時打開多個文件虚倒,用逗號分隔開即可

with open('a.txt','r') as read_f,open('b.txt','w') as write_f:

data=read_f.read()

write_f.write(data)


2.3 指定操作文本文件的字符編碼


f=open(...)是由操作系統(tǒng)打開文件,如果打開的是文本文件产舞,會涉及到字符編碼問題魂奥,如果沒有為open指定編碼,那么打開文本文件的默認(rèn)編碼很明顯是操作系統(tǒng)說了算了易猫,操作系統(tǒng)會用自己的默認(rèn)編碼去打開文件耻煤,在windows下是gbk,在linux下是utf-8准颓。


三 文件的操作模式

3.1 控制文件讀寫操作的模式

r(默認(rèn)的):只讀

w:只寫

a:只追加寫

3.1.1 案例一:r 模式的使用

# r只讀模式: 在文件不存在時則報錯,文件存在文件內(nèi)指針直接跳到文件開頭

with open('a.txt',mode='r',encoding='utf-8') as f:

? ??res=f.read()# 會將文件的內(nèi)容由硬盤全部讀入內(nèi)存哈蝇,賦值給res

3.1.2 案例二:w 模式的使用

# w只寫模式: 在文件不存在時會創(chuàng)建空文檔,文件存在會清空文件,文件指針跑到文件開頭

with open('b.txt',mode='w',encoding='utf-8') as f:

? ? f.write('你好\n')

? ? f.write('我好\n')

? ? f.write('大家好\n')

? ? f.write('111\n222\n333\n')

#強(qiáng)調(diào):

# 1 在文件不關(guān)閉的情況下,連續(xù)的寫入,后寫的內(nèi)容一定跟在前寫內(nèi)容的后面

# 2 如果重新以w模式打開文件攘已,則會清空文件內(nèi)容

3.1.3 案例三:a 模式的使用

# a只追加寫模式: 在文件不存在時會創(chuàng)建空文檔,文件存在會將文件指針直接移動到文件末尾

with open('c.txt',mode='a',encoding='utf-8') as f:

? ? f.write('44444\n')

? ? f.write('55555\n')

#強(qiáng)調(diào) w 模式與 a 模式的異同:

# 1 相同點:在打開的文件不關(guān)閉的情況下炮赦,連續(xù)的寫入,新寫的內(nèi)容總會跟在前寫的內(nèi)容之后

# 2 不同點:以 a 模式重新打開文件样勃,不會清空原文件內(nèi)容吠勘,會將文件指針直接移動到文件末尾,新寫的內(nèi)容永遠(yuǎn)寫在最后

3.1.4 案例四:+ 模式的使用

# r+ w+ a+ :可讀可寫

#在平時工作中峡眶,我們只單純使用r/w/a剧防,要么只讀,要么只寫辫樱,一般不用可讀可寫的模式


3.2 控制文件讀寫內(nèi)容的模式

大前提: tb模式均不能單獨使用,必須與r/w/a之一結(jié)合使用

t(默認(rèn)的):文本模式

? ? 1. 讀寫文件都是以字符串為單位的

? ? 2. 只能針對文本文件

? ? 3. 必須指定encoding參數(shù)

b:二進(jìn)制模式:

? 1.讀寫文件都是以bytes/二進(jìn)制為單位的

? 2. 可以針對所有文件

? 3. 一定不能指定encoding參數(shù)

3.2.1 案例一:t 模式的使用

# t 模式:如果我們指定的文件打開模式為r/w/a峭拘,其實默認(rèn)就是rt/wt/at

with open('a.txt',mode='rt',encoding='utf-8') as f:

? ? res=f.read()

? ? print(type(res)) # 輸出結(jié)果為:<class 'str'>

with open('a.txt',mode='wt',encoding='utf-8') as f:

? ? s='abc'

? ? f.write(s) # 寫入的也必須是字符串類型

#強(qiáng)調(diào):t 模式只能用于操作文本文件,無論讀寫,都應(yīng)該以字符串為單位狮暑,而存取硬盤本質(zhì)都是二進(jìn)制的形式鸡挠,當(dāng)指定 t 模式時,內(nèi)部幫我們做了編碼與解碼

3.2.2 案例二: b 模式的使用

# b: 讀寫都是以二進(jìn)制位單位

with open('1.mp4',mode='rb') as f:

? ? data=f.read()

? ? print(type(data)) # 輸出結(jié)果為:<class 'bytes'>

with open('a.txt',mode='wb') as f:

? ? msg="你好"

? ? res=msg.encode('utf-8') # res為bytes類型

? ? f.write(res) # 在b模式下寫入文件的只能是bytes類型

#強(qiáng)調(diào):b模式對比t模式

1心例、在操作純文本文件方面t模式幫我們省去了編碼與解碼的環(huán)節(jié)宵凌,b模式則需要手動編碼與解碼,所以此時t模式更為方便

2止后、針對非文本文件(如圖片瞎惫、視頻溜腐、音頻等)只能使用b模式

# 小練習(xí): 編寫拷貝工具

src_file=input('源文件路徑: ').strip()

dst_file=input('目標(biāo)文件路徑: ').strip()

with open(r'%s' %src_file,mode='rb') as read_f,open(r'%s' %dst_file,mode='wb') as write_f:

? ? for line in read_f:

? ? ? ? # print(line)

? ? ? ? write_f.write(line)

四 操作文件的方法

4.1 重點

# 讀操作

f.read()? # 讀取所有內(nèi)容,執(zhí)行完該操作后,文件指針會移動到文件末尾

f.readline()? # 讀取一行內(nèi)容,光標(biāo)移動到第二行首部

f.readlines()? # 讀取每一行內(nèi)容,存放于列表中

# 強(qiáng)調(diào):

# f.read()與f.readlines()都是將內(nèi)容一次性讀入內(nèi)容瓜喇,如果內(nèi)容過大會導(dǎo)致內(nèi)存溢出挺益,若還想將內(nèi)容全讀入內(nèi)存,則必須分多次讀入乘寒,有兩種實現(xiàn)方式:

# 方式一

with open('a.txt',mode='rt',encoding='utf-8') as f:

? ? for line in f:

? ? ? ? print(line) # 同一時刻只讀入一行內(nèi)容到內(nèi)存中

# 方式二

with open('1.mp4',mode='rb') as f:

? ? while True:

? ? ? ? data=f.read(1024) # 同一時刻只讀入1024個Bytes到內(nèi)存中

? ? ? ? if len(data) == 0:

? ? ? ? ? ? break

? ? ? ? print(data)

# 寫操作

f.write('1111\n222\n')? # 針對文本模式的寫,需要自己寫換行符

f.write('1111\n222\n'.encode('utf-8'))? # 針對b模式的寫,需要自己寫換行符

f.writelines(['333\n','444\n'])? # 文件模式

f.writelines([bytes('333\n',encoding='utf-8'),'444\n'.encode('utf-8')]) #b模式

4.2 補(bǔ)充

f.readable() # 文件是否可讀

f.writable()? # 文件是否可讀

f.closed? # 文件是否關(guān)閉

f.encoding? # 如果文件打開模式為b,則沒有該屬性

f.flush()? # 立刻將文件內(nèi)容從內(nèi)存刷到硬盤

f.name

五 主動控制文件內(nèi)指針移動

#大前提:文件內(nèi)指針的移動都是Bytes為單位的,唯一例外的是t模式下的read(n),n以字符為單位

with open('a.txt',mode='rt',encoding='utf-8') as f:

? ? data=f.read(3) # 讀取3個字符

with open('a.txt',mode='rb') as f:

? ? data=f.read(3) # 讀取3個Bytes

# 之前文件內(nèi)指針的移動都是由讀/寫操作而被動觸發(fā)的望众,若想讀取文件某一特定位置的數(shù)據(jù),則則需要用f.seek方法主動控制文件內(nèi)指針的移動伞辛,詳細(xì)用法如下:

# f.seek(指針移動的字節(jié)數(shù),模式控制):

# 模式控制:

# 0: 默認(rèn)的模式,該模式代表指針移動的字節(jié)數(shù)是以文件開頭為參照的

# 1: 該模式代表指針移動的字節(jié)數(shù)是以當(dāng)前所在的位置為參照的

# 2: 該模式代表指針移動的字節(jié)數(shù)是以文件末尾的位置為參照的

# 強(qiáng)調(diào):其中0模式可以在t或者b模式使用,而1跟2模式只能在b模式下用

5.1 案例一: 0模式詳解

# a.txt用utf-8編碼烂翰,內(nèi)容如下(abc各占1個字節(jié),中文“你好”各占3個字節(jié))

abc你好

# 0模式的使用

with open('a.txt',mode='rt',encoding='utf-8') as f:

? ? f.seek(3,0)? ? # 參照文件開頭移動了3個字節(jié)

? ? print(f.tell()) # 查看當(dāng)前文件指針距離文件開頭的位置蚤氏,輸出結(jié)果為3

? ? print(f.read()) # 從第3個字節(jié)的位置讀到文件末尾甘耿,輸出結(jié)果為:你好

? ? # 注意:由于在t模式下,會將讀取的內(nèi)容自動解碼竿滨,所以必須保證讀取的內(nèi)容是一個完整中文數(shù)據(jù)佳恬,否則解碼失敗

with open('a.txt',mode='rb') as f:

? ? f.seek(6,0)

? ? print(f.read().decode('utf-8')) #輸出結(jié)果為: 好

5.2 案例二: 1模式詳解

# 1模式的使用

with open('a.txt',mode='rb') as f:

? ? f.seek(3,1) # 從當(dāng)前位置往后移動3個字節(jié),而此時的當(dāng)前位置就是文件開頭

? ? print(f.tell()) # 輸出結(jié)果為:3

? ? f.seek(4,1)? ? # 從當(dāng)前位置往后移動4個字節(jié)于游,而此時的當(dāng)前位置為3

? ? print(f.tell()) # 輸出結(jié)果為:7

5.3 案例三: 2模式詳解

# a.txt用utf-8編碼毁葱,內(nèi)容如下(abc各占1個字節(jié),中文“你好”各占3個字節(jié))

abc你好

# 2模式的使用

with open('a.txt',mode='rb') as f:

? ? f.seek(0,2)? ? # 參照文件末尾移動0個字節(jié)贰剥, 即直接跳到文件末尾

? ? print(f.tell()) # 輸出結(jié)果為:9

? ? f.seek(-3,2)? ? # 參照文件末尾往前移動了3個字節(jié)

? ? print(f.read().decode('utf-8')) # 輸出結(jié)果為:好

# 小練習(xí):實現(xiàn)動態(tài)查看最新一條日志的效果

import time

with open('access.log',mode='rb') as f:

? ? f.seek(0,2)

? ? while True:

? ? ? ? line=f.readline()

? ? ? ? if len(line) == 0:

? ? ? ? ? ? # 沒有內(nèi)容

? ? ? ? ? ? time.sleep(0.5)

? ? ? ? else:

? ? ? ? ? ? print(line.decode('utf-8'),end='')

六 文件的修改

# 文件a.txt內(nèi)容如下

張一蛋? ? 山東? ? 179? ? 49? ? 12344234523

李二蛋? ? 河北? ? 163? ? 57? ? 13913453521

王全蛋? ? 山西? ? 153? ? 62? ? 18651433422

# 執(zhí)行操作

with open('a.txt',mode='r+t',encoding='utf-8') as f:

? ? f.seek(9)

? ? f.write('<婦女主任>')

# 文件修改后的內(nèi)容如下

張一蛋<婦女主任> 179? ? 49? ? 12344234523

李二蛋? ? 河北? ? 163? ? 57? ? 13913453521

王全蛋? ? 山西? ? 153? ? 62? ? 18651433422

# 強(qiáng)調(diào):

# 1倾剿、硬盤空間是無法修改的,硬盤中數(shù)據(jù)的更新都是用新內(nèi)容覆蓋舊內(nèi)容

# 2、內(nèi)存中的數(shù)據(jù)是可以修改的

文件對應(yīng)的是硬盤空間,硬盤不能修改對應(yīng)著文件本質(zhì)也不能修改, 那我們看到文件的內(nèi)容可以修改,是如何實現(xiàn)的呢? 大致的思路是將硬盤中文件內(nèi)容讀入內(nèi)存,然后在內(nèi)存中修改完畢后再覆蓋回硬盤 具體的實現(xiàn)方式分為兩種:

6.1 文件修改方式一

# 實現(xiàn)思路:以讀的方式打開原文件,以寫的方式打開一個臨時文件,一行行讀取原文件內(nèi)容,修改完后寫入臨時文件...,刪掉原文件,將臨時文件重命名原文件名

# 優(yōu)點: 不會占用過多的內(nèi)存

# 缺點: 在文件修改過程中同一份數(shù)據(jù)存了兩份

import os

with open('db.txt',mode='rt',encoding='utf-8') as read_f,\

? ? ? ? open('.db.txt.swap',mode='wt',encoding='utf-8') as wrife_f:

? ? for line in read_f:

? ? ? ? wrife_f.write(line.replace('SB','kevin'))

os.remove('db.txt')

os.rename('.db.txt.swap','db.txt')

6.2 文件修改方式二

# 實現(xiàn)思路:將文件內(nèi)容發(fā)一次性全部讀入內(nèi)存,然后在內(nèi)存中修改完畢后再覆蓋寫回原文件

# 優(yōu)點: 在文件修改過程中同一份數(shù)據(jù)只有一份

# 缺點: 會過多地占用內(nèi)存

with open('db.txt',mode='rt',encoding='utf-8') as f:

? ? data=f.read()

with open('db.txt',mode='wt',encoding='utf-8') as f:

? ? f.write(data.replace('kevin','SB'))

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鸠澈,一起剝皮案震驚了整個濱河市柱告,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌笑陈,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件葵袭,死亡現(xiàn)場離奇詭異涵妥,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)坡锡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門蓬网,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人鹉勒,你說我怎么就攤上這事帆锋。” “怎么了禽额?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵锯厢,是天一觀的道長皮官。 經(jīng)常有香客問我,道長实辑,這世上最難降的妖魔是什么捺氢? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮剪撬,結(jié)果婚禮上摄乒,老公的妹妹穿的比我還像新娘。我一直安慰自己残黑,他們只是感情好馍佑,可當(dāng)我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著梨水,像睡著了一般拭荤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上冰木,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天穷劈,我揣著相機(jī)與錄音,去河邊找鬼踊沸。 笑死歇终,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的逼龟。 我是一名探鬼主播评凝,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼腺律!你這毒婦竟也來了奕短?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤匀钧,失蹤者是張志新(化名)和其女友劉穎翎碑,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體之斯,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡日杈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了佑刷。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片莉擒。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖瘫絮,靈堂內(nèi)的尸體忽然破棺而出涨冀,到底是詐尸還是另有隱情,我是刑警寧澤麦萤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布鹿鳖,位于F島的核電站扁眯,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏栓辜。R本人自食惡果不足惜恋拍,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望藕甩。 院中可真熱鬧施敢,春花似錦、人聲如沸狭莱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽腋妙。三九已至默怨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間骤素,已是汗流浹背匙睹。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留济竹,地道東北人痕檬。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像送浊,于是被迫代替她去往敵國和親梦谜。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,700評論 2 354