第8天檔案操作
1. 檔案操作
檔案就是計算機的作業系統虛擬給使用者操作硬碟的一個介面。我們都知道,記憶體和硬碟都是儲存資料的,但是記憶體的資料易丟失,當我們需要在下次啟動計算機的時候還能夠看到我們寫的東西,就必須要把我們的東西寫入到硬碟中,這也就是檔案存在的意義。
操作檔案的三個步驟 1. 開啟檔案得到一個檔案控制代碼2. 通過這個檔案控制代碼來對檔案進行我們想要的操作3. 向作業系統傳送關閉指令,回收作業系統資源
2. 開啟檔案的模式
開啟檔案的模式總共有五種,三種純淨模式,r, w, a, 以及控制開啟檔案格式的兩種模式: t, b
''' 控制檔案格式的兩種模式必須和三種純淨模式一塊進行使用,不能單獨使用: 三種純淨模式: r: 只讀,檔案指標在預設在開頭,檔案不存在就跑出異常 w: 只寫,檔案指標也在開頭,檔案不存在就建立,存在就清空內容寫入 a: 追加寫入,檔案指標在結尾,檔案不存在就建立,存在就追加寫入 控制檔案格式的兩種模式: t:文字格式:只能操作文字檔案,在這樣的格式下一般需要指定處理文字的編碼方式,否則無法跨平臺進行使用
b: 二進位制格式: 可以操作所有的檔案,因此儲存就是用的位元組,所以在此模式下不能指定編碼方式 '''
(1). r只讀模式:在檔案不存在的時候報錯,檔案存在指標直接跳到開頭
簡單的開啟檔案的方式:但是不建議這樣寫,因為如果沒有指定mode和編碼方式,採取的都是預設的,mode為rt,編碼方式為作業系統預設的編碼,如果一旦出現了跨平臺的操作,就會出現亂碼的問題!
with open('user_gbk') as f: print(f.readline(11))# 無論開啟什麼檔案,都建議指定模式和編碼方式with open('user_gbk', mode='rt', encoding='gbk') as f: print(f.read())
檔案讀取的兩種模式之 【rt】模式
# 以rt模式開啟的建議指定上字元編碼,單位為字元 with open('user_utf-8', 'rt', encoding='utf-8') as f: # 把一個檔案全部的內容讀取出來,返回一個字串,一般不建議這樣讀檔案,容易撐爆記憶體 # data = f.read() # print(data, type(data), len(data)) # 讀取當前指標所在行的值,傳遞的引數代表的是讀取幾個字元 data = f.readline(4) print(data) # 把每一行的值轉換成一個字串,最後返回一個列表data = f.readlines() print(data)
檔案讀取的兩種模式之 【rb】模式
# 以rb模式開啟的不能指定字元編碼,單位都是位元組 with open('user_utf-8', 'rb') as f: # for line in f: # print(len(line)) # 把一個檔案全部的內容讀取出來,返回一個bytes型別,一般不建議這樣讀檔案,容易撐爆記憶體 # 如果我們想檢視內容,就用寫入檔案編碼方式解碼 # data = f.read() # print(data, type(data), len(data), data.decode('utf-8')) # 讀取當前指標所在行的值,傳遞的引數代表的是讀取幾個位元組 data = f.readline(3) print(data) # 把每一行的值轉換成bytes型別,最後返回一個列表 data = f.readlines() print(data)
例題:以rb的形式讀取一張圖片
with open('ceshi.png', 'rb') as f: data = f.read() print(data)
(2)r只寫模式:在檔案不存在的時候建立,檔案存在指標直接跳到開頭,覆蓋寫入檔案
檔案寫入的兩種模式之 【wt】模式
# wt的模式寫入的必須是字串 with open('user_utf-8', 'wt', encoding='utf-8') as f: f.write('中國你好!'.encode('utf-8')) line = ['111', '222', '444'] # 下面這兩種方法是一樣的 for i in line: f.write(i) f.writelines(line)
檔案寫入的兩種模式之 【wb】模式
# 寫入的是位元組,因此當我們在寫入的時候建立了 # 一個字串需要先進行編碼才能夠進行寫入 with open('user_utf-8', 'wb') as f: f.write('中國你好好!'.encode('utf-8'))
(3).a只寫模式:在檔案不存在的時候建立,檔案存在指標直接跳到檔案結尾,追加寫入檔案,和w的區別就是一個是清空寫入,一個是追加寫入,其他的都是一樣的。
例題:做一個簡單的拷貝檔案的工具
# 拷貝檔案的小工具 src_file = input('原始檔路徑>>').strip() dst_file = input('目的檔案路徑>>').strip() with open(src_file, 'rb') as read_f, open(dst_file, 'wb') as write_f: for line in read_f: write_f.write(line)
3. 檔案內游標的移動
游標的移動在【rt】模式下是是字元為單位的,但是在【rb】的形式下是以位元組為單位的
# rt模式 讀的是字元 with open('user_utf-8', 'rt', encoding='utf-8') as f: data = f.read(3) print(data) # rb模式,讀的是位元組,如果想顯示出原始的字元,得先進行解碼 with open('user_gbk', 'rb') as f: # data = f.read(3) # b'\xe4\xb8\xad' data = f.read(2) print(data, data.decode('gbk'))
控制檔案指標移動的方法:
f.seek(引數一, 引數二) 引數一: 指的是移動的位元組數 引數二:0 模式是預設模式,在任何的開啟方式下都可以使用,但是1,和2 只能在b模式下才可以進行使用 0:檔案指標以檔案開頭為參照移動【引數一】個位元組數,移動的位元組數不能為負 1: 檔案指標以當前指標所在位置為參照移動【引數一】個位元組數, 負數為左,正數為右 2: 檔案指標以檔案末尾為參照移動【引數一】個位元組數f.tell() 檢視當前指標離檔案頭部的位元組數
0模式:
# f.seek的0模式,f.seek的指標都是以位元組形式移動的 # 在我們人為操作移動的過程中,不能把一個字元給拆分開 # 否則在列印的時候會報錯 # rt模式 with open('user_utf-8', 'rt', encoding='utf-8') as f: f.read() f.seek(3, 0) print(f.tell()) print(f.read()) # rb模式 with open('user_utf-8', 'rb') as f: f.seek(3, 0) print(f.tell()) print(f.read().decode('utf-8'))
1 模式
# f.seek的1模式, # 1.只能在b模式下進行使用 # 2.偏移量可負可正,負為左,正為右 # 3.指標移動不能拆分字元,否則在解碼的時候會報錯 with open('user_utf-8', 'rb') as f: f.read() f.seek(-3, 1) print(f.read().decode('utf-8'))
2 模式
# f.seek的2模式 # 1. 只能在b模式下使用 # 2. 偏移量可正可負,正返回為空,負代表指標移動 # 3.指標移動不能拆分字元,否則在解碼的時候會報錯 with open('user_utf-8', 'rb') as f: f.seek(-3, 2) print(f.read().decode('utf-8'))
例題:tail -f access.log 模擬當前命令
command = input('請輸入命令(Q退出)>>').strip() while True: try: if command.upper() == 'Q': break if command.split()[0] == 'tail' and command.split()[1] == '-f': # 輸入的命令沒有錯誤,獲取檔名 file_path = command.split()[2] print(file_path) with open(file_path, 'rb') as f: # 移動指標到尾部 f.seek(0, 2) while True: line = f.readline() # 如果沒有檔案匯入,就繼續迴圈 if len(line) == 0: continue else: # 如果有檔案匯入就寫入檔案 print(line.decode('utf-8')) else: print('usage: tail -f file_path!') except: print('usage: tail -f file_path!')
4. 檔案的修改
檔案就是計算機的作業系統給我們對映的一塊硬碟空間。對於硬碟而言,是沒有辦法修改的,我們對於硬碟的操作也只能是覆蓋寫入,因此檔案也是不能修改的。但是我們會發現,我們每次開啟檔案的是可以對其進行的修改的,這究竟是怎麼回事呢?是因為記憶體。我們的資料在硬碟上是沒有辦法修改,但是在記憶體中確是可以進行修改的,因此我們通常所說的檔案修改其實指的就是記憶體的修改。通過記憶體修改完成之後重新寫入硬碟中的。
檔案修改的兩種方式:
1. 把檔案全部載入到記憶體中,然後在記憶體中修改我們的資料,之後統一的寫入檔案中 優點:在檔案修改過程中同一份資料只有一份 缺點:會佔用過多的記憶體
2. 把檔案一行一行的載入到記憶體中,一行行的修改之後寫入到一個新的檔案,當修改完成之後,刪除原始檔,然後把新的檔名字改成原始檔的名字。 優點:不會佔用過多的記憶體 缺點:在檔案修改過程中,會有兩份資料存在硬碟中。
驗證硬盤裡的資料是不能修改的:
檔案內容:
你好,啊slegeg
我好
大家好
# 檔案內容: ''' 你好,啊slegega 我好 大家好 ''' with open('user_utf-8', 'r+t', encoding='utf-8') as f: # 移動指標到第一行的【啊】後面 f.seek(12, 0) # 寫入【中國好】三個字 # 如果硬碟資料能夠進行修改第一行一概出現:你好,啊中國好slegega # 如果硬碟不能改只能覆蓋,應該出現:你好,啊中國好我好(因為把這一行後面的換行符也去掉了) f.write('中國好')
檔案的修改方法:
檔案內容:
kevin is dsb dsb is kevin alex is kevin
第一種方式的把kevin全部改成SB
# 內容全部載入到記憶體 with open('a.txt', 'rt', encoding='utf-8') as f: res = f.read().replace('kevin', 'SB') # 將修改的資料重新寫入檔案中 with open('a.txt', 'wt', encoding='utf-8') as f: f.write(res)
第二種方式把所有‘SB'全部改成kevin
# 首先開啟以rt得方式開啟原始檔,然後以wt的形式開啟一個新檔案 with open('a.txt', 'rt', encoding='utf-8') as read_file,\ open('.a.txt.swap', 'wt', encoding='utf-8') as write_file: # 修改一個值並寫入到一個新的檔案中 for line in read_file: res = line.replace('SB', 'kevin') write_file.write(res) import os os.remove('a.txt') os.rename('.a.txt.swap', 'a.txt')