目錄python
應用程序運行過程當中產生的數據最早都是存放於內存中的,若想永久保存下來,必需要保存於硬盤中。應用程序若想操做硬件必須經過操做系統,而文件就是操做系統提供給應用程序來操做硬盤的虛擬概念,用戶或應用程序對文件的操做,就是向操做系統發起調用,而後由操做系統完成對硬盤的具體操做。linux
有了文件的概念,咱們無需再去考慮操做硬盤的細節,只須要關注操做文件的流程:windows
# 1. 打開文件,由應用程序向操做系統發起系統調用open(...),操做系統打開該文件,對應一塊硬盤空間,並返回一個文件對象賦值給一個變量f f=open('a.txt','r',encoding='utf-8') #默認打開模式就爲r # 2. 調用文件對象下的讀/寫方法,會被操做系統轉換爲讀/寫硬盤的操做 data=f.read() # 3. 向操做系統發起關閉文件的請求,回收系統資源 f.close()
打開一個文件包含兩部分資源:應用程序的變量f和操做系統打開的文件。在操做完畢一個文件時,必須把與該文件的這兩部分資源所有回收,回收方法爲:函數
一、f.close() #回收操做系統打開的文件資源 二、del f #回收應用程序級的變量
其中del f
必定要發生在f.close()
以後,不然就會致使操做系統打開的文件沒法關閉,白白佔用資源,
而python自動的垃圾回收機制決定了咱們無需考慮del f
,這就要求咱們,在操做完畢文件後,必定要記住f.close()
,雖然咱們如此強調,可是大多數讀者仍是會不禁自主地忘記f.close()
,考慮到這一點,python提供了with
關鍵字來幫咱們管理上下文工具
# 一、在執行完子代碼塊後,with 會自動執行f.close() with open('a.txt', mode='w', coding='utf-8') as f: pass # 二、可用用with同時定義讀和寫,用逗號分隔開便可 with open(r'test.txt', mode='r', encoding='utf-8') as rf,\ open(r'test.txt', mode='r', encoding='utf-8') as rw: print(rf.read()) # 打印出所有讀取到的內容
f = open(...)是由操做系統打開文件,若是打開的是文本文件,會涉及到字符編碼問題,若是沒有爲open指定編碼,那麼打開文本文件的默認編碼很明顯是操做系統說了算了,操做系統會用本身的默認編碼去打開文件,在windows下是gbk,在linux下是utf-8。 這就用到了上節課講的字符編碼的知識:若要保證不亂碼,文件以什麼方式存的,就要以什麼方式打開。 f = open('a.txt','r',encoding='utf-8')
r(默認的):只讀 w:只寫 a:只追加寫
# r只讀模式: 在文件不存在時,則會報錯;文件存在時,文件內指針直接跳到文件開頭 with open('a.txt',mode='r',encoding='utf-8') as f: res=f.read() # 會將文件的內容由硬盤所有讀入內存,賦值給res # 小練習:實現用戶認證功能 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('帳號名或者密碼錯誤') # db.txt ------> kody:123
# w只寫模式: 在文件不存在時會建立空文檔,文件存在會清空文件,文件指針跑到文件開頭 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 在文件不關閉的狀況下,連續的寫入,後寫的內容必定跟在前寫內容的後面 # 2 若是從新以w模式打開文件,則會清空文件內容
# a只追加寫模式: 在文件不存在時會建立空文檔,文件存在會將文件指針直接移動到文件末尾追加新數據 with open('c.txt',mode='a',encoding='utf-8') as f: f.write('44444\n') f.write('55555\n') #強調 w 模式與 a 模式的異同: # 1 相同點:在打開的文件不關閉的狀況下,連續的寫入,新寫的內容總會跟在前寫的內容以後 # 2 不一樣點:以 a 模式從新打開文件,不會清空原文件內容,會將文件指針直接移動到文件末尾,新寫的內容永遠寫在最後 # 小練習:實現註冊功能: 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參數 # b:二進制模式: 1.讀寫文件都是以bytes/二進制爲單位的 2. 能夠針對全部文件,針對非文本文件(如圖片、視頻、音頻等) 3. 必定不能指定encoding參數
# 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 模式時,python解釋器內部幫咱們作了編碼與解碼
# 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模式 一、在操做純文本文件方面t模式幫咱們省去了編碼與解碼的環節,b模式則須要手動編碼與解碼,因此此時t模式更爲方便 二、針對非文本文件(如圖片、視頻、音頻等)只能使用b模式 # 小練習: 編寫拷貝工具 with open(r'冬季.png', 'rb') as rb, \ open(r'冬季.jpg', 'wb') as wb: jpg = rb.read() wb.write(jpg)
# 讀操做 f.read() # 讀取全部內容,執行完該操做後,文件指針會移動到文件末尾 f.readline() # 讀取一行內容,光標移動到第二行首部 f.readlines() # 讀取每一行內容,存放於列表中 # 強調: # f.read()與f.readlines()都是將內容一次性讀入內容,若是內容過大會致使內存溢出,若還想將內容全讀入內存,則必須分屢次讀入,有兩種實現方式: # 方式一 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 # 寫文件 f.writeable # 是否可寫 f.writelines() # for + f.write() 循環寫入多條 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
#大前提:文件內指針的移動都是Bytes爲單位的,惟一例外的是t模式下的read(n),n以字符爲單位 f.seek(offset,whence) offset: 相對偏移度 (光標移動的位數)針對的是字節 whence:指定光標位置從何開始 0:從文件開頭 1:從當前位置 2:從文件末尾 補充: utf-8: 中文是3個bytes 英文是1個bytes gbk: 所有都是2個bytes open函數不設置encoding,默認是gbk 與encode一毛錢都沒有,encoding只是一個參數 除了read裏面的參數是針對字符,其餘都是針對字節
# a.txt用utf-8編碼,內容以下(abc各佔1個字節,中文「你好」各佔3個字節) abc你好 # 0模式的使用 with open('a.txt',mode='rt',encoding='utf-8') as f: f.seek(3,0) # 參照文件開頭移動了3個字節 print(f.tell()) # 查看當前文件指針距離文件開頭的位置,輸出結果爲3 print(f.read()) # 從第3個字節的位置讀到文件末尾,輸出結果爲:你好 # 注意:因爲在t模式下,會將讀取的內容自動解碼,因此必須保證讀取的內容是一個完整中文數據,不然解碼失敗 with open('a.txt',mode='rb') as f: f.seek(6,0) print(f.read().decode('utf-8')) #輸出結果爲: 好
# 1模式的使用 with open('a.txt',mode='rb') as f: f.seek(3,1) # 從當前位置日後移動3個字節,而此時的當前位置就是文件開頭 print(f.tell()) # 輸出結果爲:3 f.seek(4,1) # 從當前位置日後移動4個字節,而此時的當前位置爲3 print(f.tell()) # 輸出結果爲:7
# a.txt用utf-8編碼,內容以下(abc各佔1個字節,中文「你好」各佔3個字節) abc你好 # 2模式的使用 with open('a.txt',mode='rb') as f: f.seek(0,2) # 參照文件末尾移動0個字節, 即直接跳到文件末尾 print(f.tell()) # 輸出結果爲:9 f.seek(-3,2) # 參照文件末尾往前移動了3個字節 print(f.read().decode('utf-8')) # 輸出結果爲:好 # 小練習:實現動態查看最新一條日誌的效果 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='')
寫入文件腳本:編碼
# encoding:utf-8 import time res = time.strftime('%Y-%m-%d %H:%M:%S') print(res) with open('a.txt', 'a', encoding='utf-8') as af: af.write(f'獲取時間爲:{res}\n')
獲取文件實時動態:操作系統
# encoding:utf-8 import time with open(r'a.txt', 'r', encoding='utf-8') as rf: while True: res = rf.readline() # 一次讀取一行 if res: print(f'捕捉新增記錄:{res}')
# 文件a.txt內容以下 張一蛋 山東 179 49 12344234523 李二蛋 河北 163 57 13913453521 王全蛋 山西 153 62 18651433422 # 執行操做 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 # 強調: # 一、硬盤空間是沒法修改的,硬盤中數據的更新都是用新內容覆蓋舊內容 # 二、內存中的數據是能夠修改的
文件對應的是硬盤空間,硬盤不能修改對應着文件本質也不能修改,
那咱們看到文件的內容能夠修改,是如何實現的呢?
大體的思路是將硬盤中文件內容讀入內存,而後在內存中修改完畢後再覆蓋回硬盤
具體的實現方式分爲兩種:指針
# 實現思路:將文件內容一次性所有讀入內存,而後在內存中修改完畢後再覆蓋寫回原文件 # 優勢: 在文件修改過程當中同一份數據只有一份 # 缺點: 會過多地佔用內存 with open('a.txt', 'r+', encoding='utf-8') as r_f: data = r_f.read() with open('a.txt', 'w+', encoding='utf-8') as w_f: w_f.write(data.replace('張一蛋', '張一蛋<婦女主任>')) 張一蛋<婦女主任> 山東 179 49 12344234523 李二蛋 河北 163 57 13913453521 王全蛋 山西 153 62 18651433422
# 實現思路:以讀的方式打開原文件,以寫的方式打開一個臨時文件,一行行讀取原文件內容,修改完後寫入臨時文件...,刪掉原文件,將臨時文件重命名原文件名 # 優勢: 不會佔用過多的內存 # 缺點: 在文件修改過程當中同一份數據存了兩份 import os with open(r'a.txt', mode='rt', encoding='utf-8') as rf,\ open(r'b.txt', mode='wt', encoding='utf-8') as wf: for line in rf: wf.write(line.replace('張一蛋', '張一蛋<婦女主任>')) os.remove('a.txt') os.rename('b.txt', 'a.txt')