第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‘)
第8天文件操作