Python文件處理與垃圾回收機制詳情
01、文件操作
文件是操作系統(tǒng)提供給用戶/應用程序操作硬盤的一個虛擬的概念/接口
用戶/應用程序可以通過文件將數(shù)據(jù)永久保存在硬盤中
用戶/應用程序直接操作的是文件,對文件進行的所有的操作,都是在向操作系統(tǒng)發(fā)送系統(tǒng)調用,然后再由操作系統(tǒng)將其轉成具體的硬盤操作
1.1、文件操作流程
打開文件:
打開文件,由應用系統(tǒng)向操作系統(tǒng)發(fā)起系統(tǒng)調用open(),操作系統(tǒng)打開該文件,對應一塊硬盤空間,并返回一個文件對象賦值給一個變量f
"""Windows路徑分隔符問題""" """方案1 (推薦)""" f=open(r'C:\a\b\c\d.txt',mode='rt')#r原生字符串rawstring """方案2""" f=open(r'C:/a/b/c/d.txt')
操作文件(讀/寫):
調用文件對象下的讀/寫方法,會被操作系統(tǒng)轉換為讀/寫硬盤的操作
f.read()
關閉文件:
向操作系統(tǒng)發(fā)起關閉文件的請求,回收系統(tǒng)資源
f.close()
with上下文管理:
#1. 執(zhí)行完代碼后,with會自動執(zhí)行fp.close() with open('a.txt',mode='rt')as fp: res=fp.read()#t模式會將fp.read()讀出來的結果解碼成unicode print(res) #2. 用with打開多個文件,用逗號分割開即可 with open('a.txt','r') as f1,open('b.txt','r')as f2: res1=f1.read() res2=f2.read() print(res1) print(res2)
指定操作文件的字符編碼
""" f=open(....)由操作系統(tǒng)打開文件,如果打開的是文本文件,會涉及到字符編碼問題,如果沒有為open指定編碼,那么打開文本文件的默認編碼是操作系統(tǒng)說了算的, 操作系統(tǒng)會用自己默認的編碼去打開文件,在windos下是gbk,在Linux下是utf-8 """
1.2、文件的操作模式
控制文件讀寫操作的模式
""" r(默認的)只讀 w:只寫 a:只追加寫 """
r模式使用:
# r只讀模式: 在文件不存在時則報錯,文件存在文件內指針直接跳到文件開頭 with open('a.txt',mode='r',encoding='utf-8') as f: res=f.read() # 會將文件的內容由硬盤全部讀入內存,賦值給res # 小練習:實現(xiàn)用戶認證功能 inp_name=input('請輸入你的名字: ').strip() inp_pwd=input('請輸入你的密碼: ').strip() with open(r'db.txt',mode='r',encoding='utf-8') as f: for line in f: # 把用戶輸入的名字與密碼與讀出內容做比對 u,p=line.strip('\n').split(':') if inp_name == u and inp_pwd == p: print('登錄成功') break else: print('賬號名或者密碼錯誤')
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') #強調: # 1 在文件不關閉的情況下,連續(xù)的寫入,后寫的內容一定跟在前寫內容的后面 # 2 如果重新以w模式打開文件,則會清空文件內容 #案例:w模式用來創(chuàng)建全新的文件 #文件的copy工具 src_file=input("源文件路徑》》").strip() dsc_file=input("源文件路徑》》").strip() with open(r'{}'.format(src_file),mode='rt',encoding='utf-8')as f1,open(r'{}'.format(dsc_file),mode='wt',encoding='utf-8')as f2: res=f1.read() f2.write(res)
a模式的使用:
# a只追加寫模式: 在文件不存在時會創(chuàng)建空文檔,文件存在會將文件指針直接移動到文件末尾 with open('c.txt',mode='a',encoding='utf-8') as f: f.write('44444\n') f.write('55555\n') #強調 w 模式與 a 模式的異同: # 1 相同點:在打開的文件不關閉的情況下,連續(xù)的寫入,新寫的內容總會跟在前寫的內容之后 # 2 不同點:以 a 模式重新打開文件,不會清空原文件內容,會將文件指針直接移動到文件末尾,新寫的內容永遠寫在最后 # 小練習:實現(xiàn)注冊功能:把用戶名和密碼添加至數(shù)據(jù)庫 name=input('username>>>: ').strip() pwd=input('password>>>: ').strip() with open('db1.txt',mode='a',encoding='utf-8') as f: info='%s:%s\n' %(name,pwd) f.write(info)
+模式的使用
# r+ w+ a+ :可讀可寫 #在平時工作中,我們只單純使用r/w/a,要么只讀,要么只寫,一般不用可讀可寫的模式
控制文件讀寫內容的模式
大前提: tb模式均不能單獨使用,必須與r/w/a之一結合使用
t(默認的):文本模式
- 1. 讀寫文件都是以字符串為單位的
- 2. 只能針對文本文件
- 3. 必須指定encoding參數(shù)
b:二進制模式:
- 1.讀寫文件都是以bytes/二進制為單位的
- 2. 可以針對所有文件
- 3. 一定不能指定encoding參數(shù)
t模式的使用:
# t 模式:如果我們指定的文件打開模式為r/w/a,其實默認就是rt/wt/at with open('a.txt',mode='rt',encoding='utf-8') as f: res=f.read() print(type(res)) # 輸出結果為:<class 'str'> with open('a.txt',mode='wt',encoding='utf-8') as f: s='abc' f.write(s) # 寫入的也必須是字符串類型 #強調:t 模式只能用于操作文本文件,無論讀寫,都應該以字符串為單位,而存取硬盤本質都是二進制的形式,當指定 t 模式時,內部幫我們做了編碼與解碼
b模式的使用:
# b: 讀寫都是以二進制位單位 with open('1.mp4',mode='rb') as f: data=f.read() print(type(data)) # 輸出結果為:<class 'bytes'> with open('a.txt',mode='wb') as f: msg="你好" res=msg.encode('utf-8') # res為bytes類型 f.write(res) # 在b模式下寫入文件的只能是bytes類型 #強調:b模式對比t模式 1、在操作純文本文件方面t模式幫我們省去了編碼與解碼的環(huán)節(jié),b模式則需要手動編碼與解碼,所以此時t模式更為方便 2、針對非文本文件(如圖片、視頻、音頻等)只能使用b模式 # 小練習: 編寫拷貝工具 src_file=input('源文件路徑: ').strip() dst_file=input('目標文件路徑: ').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)
1.3、操作文件的方法
重點:
# 讀操作 f.read() # 讀取所有內容,執(zhí)行完該操作后,文件指針會移動到文件末尾 f.readline() # 讀取一行內容,光標移動到第二行首部 f.readlines() # 讀取每一行內容,存放于列表中 # 強調: # f.read()與f.readlines()都是將內容一次性讀入內容,如果內容過大會導致內存溢出,若還想將內容全讀入內存,則必須分多次讀入,有兩種實現(xiàn)方式: # 方式一 with open('a.txt',mode='rt',encoding='utf-8') as f: for line in f: print(line) # 同一時刻只讀入一行內容到內存中 # 方式二 with open('1.mp4',mode='rb') as f: while True: data=f.read(1024) # 同一時刻只讀入1024個Bytes到內存中 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模式
了解:
f.readable() # 文件是否可讀 f.writable() # 文件是否可讀 f.closed # 文件是否關閉 f.encoding # 如果文件打開模式為b,則沒有該屬性 f.flush() # 立刻將文件內容從內存刷到硬盤 f.name
1.4、主動移動文件內指針移動
#大前提:文件內指針的移動都是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 # 之前文件內指針的移動都是由讀/寫操作而被動觸發(fā)的,若想讀取文件某一特定位置的數(shù)據(jù),則則需要用f.seek方法主動控制文件內指針的移動,詳細用法如下: # f.seek(指針移動的字節(jié)數(shù),模式控制): # 模式控制: # 0: 默認的模式,該模式代表指針移動的字節(jié)數(shù)是以文件開頭為參照的 # 1: 該模式代表指針移動的字節(jié)數(shù)是以當前所在的位置為參照的 # 2: 該模式代表指針移動的字節(jié)數(shù)是以文件末尾的位置為參照的 # 強調:其中0模式可以在t或者b模式使用,而1跟2模式只能在b模式下用
0模式:
只有0模式可以在t下使用,1,2必須在b模式下使用
# a.txt用utf-8編碼,內容如下(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()) # 查看當前文件指針距離文件開頭的位置,輸出結果為3 print(f.read()) # 從第3個字節(jié)的位置讀到文件末尾,輸出結果為:你好 # 注意:由于在t模式下,會將讀取的內容自動解碼,所以必須保證讀取的內容是一個完整中文數(shù)據(jù),否則解碼失敗 with open('a.txt',mode='rb') as f: f.seek(6,0) print(f.read().decode('utf-8')) #輸出結果為: 好
1模式:
# 1模式的使用 with open('a.txt',mode='rb') as f: f.seek(3,1) # 從當前位置往后移動3個字節(jié),而此時的當前位置就是文件開頭 print(f.tell()) # 輸出結果為:3 f.seek(4,1) # 從當前位置往后移動4個字節(jié),而此時的當前位置為3 print(f.tell()) # 輸出結果為:7
2模式:
# a.txt用utf-8編碼,內容如下(abc各占1個字節(jié),中文“你好”各占3個字節(jié)) abc你好 # 2模式的使用 with open('a.txt',mode='rb') as f: f.seek(0,2) # 參照文件末尾移動0個字節(jié), 即直接跳到文件末尾 print(f.tell()) # 輸出結果為:9 f.seek(-3,2) # 參照文件末尾往前移動了3個字節(jié) print(f.read().decode('utf-8')) # 輸出結果為:好 # 小練習:實現(xiàn)動態(tài)查看最新一條日志的效果 #exe.py: with open('access.log','a',encoding='utf-8')as fp: fp.write('202120202020200 收款2000元\n') #access_log.py: import time with open('access.log',mode='rb') as f: f.seek(0,2)#將指針移到末尾 while True: line=f.readline() if len(line) == 0: # 沒有內容 time.sleep(0.5) else: print(line.decode('utf-8'),end='') """每執(zhí)行一次exe.py,access_log就會檢測到數(shù)據(jù),并打印出來"""
1.5文件的修改
# 文件a.txt內容如下 張一蛋 山東 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('<婦女主任>') # 文件修改后的內容如下 張一蛋<婦女主任> 179 49 12344234523 李二蛋 河北 163 57 13913453521 王全蛋 山西 153 62 18651433422 # 強調: # 1、硬盤空間是無法修改的,硬盤中數(shù)據(jù)的更新都是用新內容覆蓋舊內容 # 2、內存中的數(shù)據(jù)是可以修改的
文件對應的是硬盤空間,硬盤不能修改對應著文件本質也不能修改, 那我們看到文件的內容可以修改,是如何實現(xiàn)的呢? 大致的思路是將硬盤中文件內容讀入內存,然后在內存中修改完畢后再覆蓋回硬盤
具體的實現(xiàn)方式分為兩種:
方式一:
# 實現(xiàn)思路:將文件內容發(fā)一次性全部讀入內存,然后在內存中修改完畢后再覆蓋寫回原文件 # 優(yōu)點: 在文件修改過程中同一份數(shù)據(jù)只有一份 # 缺點: 會過多地占用內存 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('zhao','SB'))
方式二:
# 實現(xiàn)思路:以讀的方式打開原文件,以寫的方式打開一個臨時文件,一行行讀取原文件內容,修改完后寫入臨時文件...,刪掉原文件,將臨時文件重命名原文件名 # 優(yōu)點: 不會占用過多的內存 # 缺點: 在文件修改過程中同一份數(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')
1.6垃圾回收機制
解釋器在執(zhí)行到定義變量的語法時,會申請內存空間來存放變量的值,而內存的容量是有限的,這就涉及到變量值所占用內存空間的回收問題,當一個變量值沒有用了(簡稱垃圾)就應該將其占用的內存給回收掉,那什么樣的變量值是沒有用的呢?
單從邏輯層面分析,我們定義變量將變量值存起來的目的是為了以后取出來使用,而取得變量值需要通過其綁定的直接引用(如x=10,10被x直接引用)或間接引用(如l=[x,],x=10,10被x直接引用,而被容器類型l間接引用),所以當一個變量值不再綁定任何引用時,我們就無法再訪問到該變量值了,該變量值自然就是沒有用的,就應該被當成一個垃圾回收。
毫無疑問,內存空間的申請與回收都是非常耗費精力的事情,而且存在很大的危險性,稍有不慎就有可能引發(fā)內存溢出問題,好在Cpython解釋器提供了自動的垃圾回收機制來幫我們解決了這件事。
什么是GC:
垃圾回收機制(簡稱GC)是Python解釋器自帶一種機,專門用來回收不可用的變量值所占用的內存空間
為什么用垃圾回收機制:
程序運行過程中會申請大量的內存空間,而對于一些無用的內存空間如果不及時清理的話會導致內存使用殆盡(內存溢出),導致程序崩潰,因此管理內存是一件重要且繁雜的事情,而python解釋器自帶的垃圾回收機制把程序員從繁雜的內存管理中解放出來。
垃圾回收機制原理分析:
Python的GC模塊主要運用了“引用計數(shù)”(reference counting)來跟蹤和回收垃圾。在引用計數(shù)的基礎上,還可以通過“標記-清除”(mark and sweep)解決容器對象可能產生的循環(huán)引用的問題,并且通過“分代回收”(generation collection)以空間換取時間的方式來進一步提高垃圾回收的效率。
(一)引用計數(shù)
引用計數(shù)就是:變量值被變量名關聯(lián)的次數(shù)
如:age=18
變量值18被關聯(lián)了一個變量名age,稱之為引用計數(shù)為1
引用計數(shù)增加:
age=18 (此時,變量值18的引用計數(shù)為1)
m=age (把age的內存地址給了m,此時,m,age都關聯(lián)了18,所以變量值18的引用計數(shù)為2)
引用計數(shù)減少:
age=10(名字age先與值18解除關聯(lián),再與3建立了關聯(lián),變量值18的引用計數(shù)為1)
del m(del的意思是解除變量名x與變量值18的關聯(lián)關系,此時,變量18的引用計數(shù)為0)
值18的引用計數(shù)一旦變?yōu)?,其占用的內存地址就應該被解釋器的垃圾回收機制回收
a=12 #直接引用 b=a #間接引用
"""循環(huán)引用""" l1=[111,] l2=[222,] l1.append(l2)#l1=[值111的內存地址,l2列表的內存地址] l2.append(l1)#l2=[值222的內存地址,l1列表的內存地址] print(id(l1[1])) print(id(l2)) print(id(l2[1])) print(id(l1)) print(l2) print(l1[1]) """結果如下""" 2006853601024 2006853601024 2006561499520 2006561499520 [222, [111, [...]]] [222, [111, [...]]]
到此這篇關于Python文件處理與垃圾回收機制詳情的文章就介紹到這了,更多相關Python文件處理 內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Python OpenCV利用筆記本攝像頭實現(xiàn)人臉檢測
這篇文章主要為大家詳細介紹了Python OpenCV利用筆記本攝像頭實現(xiàn)人臉檢測,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-04-04Python Pandas數(shù)據(jù)分析工具用法實例
這篇文章主要介紹了Python Pandas數(shù)據(jù)分析工具用法實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-11-11在多種情況/開發(fā)環(huán)境中運行python腳本和代碼的技巧分享
Python腳本或程序是包含可執(zhí)行Python代碼的文件,能夠運行Python腳本和代碼可能是您作為Python開發(fā)人員所需的最重要的技能,在本教程中,您將學習一些運行Python腳本和代碼的技術,在每種情況下使用的技術將取決于您的環(huán)境、平臺、需求和技能2023-11-11使用matplotlib實現(xiàn)在同一個窗口繪制多個圖形
這篇文章主要介紹了使用matplotlib實現(xiàn)在同一個窗口繪制多個圖形問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08Python?OpenCV基于HSV的顏色分割實現(xiàn)示例
這篇文章主要為大家介紹了Python?OpenCV基于HSV的顏色分割實現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-06-06Python實現(xiàn)蟻群優(yōu)化算法的示例代碼
蟻群算法是一種源于大自然生物世界的新的仿生進化算法,本文主要介紹了Python如何實現(xiàn)蟻群算法,文中通過示例代碼具有一定的參考價值,感興趣的小伙伴們可以了解一下2023-08-08