記錄我的 python 學習歷程-Day08 檔案的操作
檔案操作的初識
用 python 程式碼對檔案進行各種操作。
基本構成:
- 檔案路徑:path
- 開啟方式:讀、寫、追加、讀寫、寫讀……
- 編碼方式:utf-8 / gbk / gb2312……
f = open('檔案路徑或者相對路',encoding='編碼方式',mode='模式') # 格式構成 cotent = f.read() print(content) f.close()
程式碼解釋:
open:
內建函式,open 底層呼叫的是作業系統的介面。
f:
變數,約定俗成的變數名有(f1,fh,file_handler,f_h),這個變數還有一個名字,叫檔案控制代碼。對亠件進行的任何操作,都得通過檔案控制代碼加'.'的方式。
encoding:
可以不寫,如果不寫,預設的編碼本就是系統預設的編碼。
Windows: gkb
Linux: utf-8
MacOS: utf-8
mode:
就是定義你的操作方式:r 為讀模式。
f.read():
你想操作檔案,比如讀檔案,給檔案寫內容,等等,都必須通過檔案控制代碼進行操作。
f.colse():
關閉檔案。(必須關閉,否則會常駐記憶體。)
檔案操作的三個步驟:
開啟檔案。
對檔案控制代碼進行相應的操作。
關閉檔案。
# 開啟檔案,得到檔案控制代碼並賦值給一個變數 f = open('檔案.txt', 'r', encoding='utf-8') # 預設開啟模式就為 r # 通過控制代碼對檔案進行操作 date = f.read() # 關閉檔案 f.close()
報錯的原因:
UnicodeDecodeError:檔案儲存時與檔案開啟時編碼本不一致。
路徑分隔符產生的問題:
解決方法:在路徑前加個 r r'C:\Users\Desktop\檔案.txt'
檔案操作的:讀
檔案操作的讀,有四種模式(r、rb、r+、r+b),r+ 和 r+b 不常用, rb 操作的是非文字的檔案,比如:圖片、視訊、音訊。每種模式有五種方法(read()、read(n)、readline()、readlines()、for)。
r 模式
以只讀方式開啟檔案,檔案的指標將會放在檔案的開頭。是檔案操作最常用的模式,也是預設模式,如果一個檔案不設定mode,那麼預設使用r模式操作檔案。
舉例:
f = open('檔案.txt', mode='r', encoding='utf-8') msg = f.read() f.close() print(msg)
read() 一次性全部讀取
read() 將檔案中的內容全部讀取出來; 弊端:如果檔案很大就會非常的佔用記憶體,容易導致記憶體崩潰。
f = open('測試', mode='r', encoding='utf-8') msg = f.read() f.close() print(msg) # 輸出結果: 這是一行測試 A:這是第二行 B:這是第三行 C:這是第幾行 D:這是我也不知道第幾行 就這麼地吧.
read(n) 指定讀取到什麼位置
在 r 模式下,n 按照字元讀取
f = open('測試', mode='r', encoding='utf-8') msg = f.read(4) f.close() print(msg) # 輸出結果: 這是一行
readline() 按行讀取
readline() 每次只讀取一行,注意: readline() 讀取出來的資料在後面都有一個\n,解決這個問題只需要在我們讀取出來的檔案後邊加一個strip()就OK了
f = open('測試', mode='r', encoding='utf-8') msg1 = f.readline() msg2 = f.readline().strip() msg3 = f.readline() msg4 = f.readline() f.close() print(msg1) print(msg2) print(msg3) print(msg4) # 輸出結果: 這是一行測試 A:這是第二行 B:這是第三行 C:這是第幾行
readlines() 返回一個列表
readlines() 返回一個列表,列表裡面每個元素是原檔案的每一行,如果檔案很大,佔記憶體,容易崩盤。
f = open('測試', mode='r', encoding='utf-8') print(f.readlines()) # 還可以這麼寫的,哈哈 f.close() # 輸出結果: ['這是一行測試\n', 'A:這是第二行\n', 'B:這是第三行\n', 'C:這是第幾行\n', 'D:這是我也不知道第幾行\n', '就這麼地吧.']
上面這四種都不太好,如果檔案超大,內容超多,他們就很容易將記憶體撐爆,所以,我們還有第五種方法。
for 迴圈
可以通過for迴圈去讀取,檔案控制代碼是一個迭代器,他的特點就是每次迴圈只在記憶體中佔一行的資料,非常節省記憶體。
f = open('測試', mode='r', encoding='utf-8') for line in f: print(line) # 去掉 \n 可以這樣寫: print(line.strip()) # 這種方式就是在一行一行的進行讀取,它就執行了下邊的功能 ''' print(f.readline()) print(f.readline()) print(f.readline()) ....... ''' # 輸出結果: 這是一行測試 A:這是第二行 B:這是第三行 C:這是第幾行 D:這是我也不知道第幾行 就這麼地吧.
特別注意: 讀完的檔案一定必須要關閉
rb 模式
rb模式:以二進位制格式開啟一個檔案用於只讀。檔案指標將會放在檔案的開頭。記住下面講的也是一樣,帶b的都是以二進位制的格式操作檔案,他們主要是操作非文字檔案:圖片,音訊,視訊等,並且如果你要是帶有b的模式操作檔案,那麼不用宣告編碼方式。
f1 = open('圖片.jpeg', mode='rb') tu = f1.read() f1.close() print(tu) # 輸出結果: b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00H\x00H\x00\x00\xff\xe1\x00\xb0Exif\x............後面還有.老長老長了..此處省略了.
rb模式也有read read(n) readline(),readlines() for迴圈這幾種方法,這裡就不一一演示了。
檔案操作的:寫
檔案操作的寫,有四種模式(w、wb、w+、w+b),w+ 和 w+b 不常用, wb 操作的是非文字的檔案,比如:圖片、視訊、音訊。操作方法是:write('要寫入的內容')
w 模式
如果檔案不存在,用 w 模式操作檔案,它會先建立檔案,然後寫入內容。
f = open('這是一個新建立的檔案', encoding='utf-8', mode='w') f.write('果然是一個新建立的檔案') f.close()
如果檔案存在,利用w模式操作檔案,先清空原檔案內容,在寫入新內容。
f = open('這是一個新建立的檔案', encoding='utf-8', mode='w') f.write('這是清空後重新寫入的內容') f.close()
wb 模式
wb模式:以二進位制格式開啟一個檔案只用於寫入。如果該檔案已存在則開啟檔案,並從開頭開始編輯,即原有內容會被刪除。如果該檔案不存在,建立新檔案。一般用於非文字檔案如:圖片,音訊,視訊等。
>>舉個例子 :
我先以rb的模式將一個圖片的內容以bytes型別全部讀取出來,然後在以wb將全部讀取出來的資料寫入一個新檔案,這樣我就完成了類似於一個圖片複製的流程。具體程式碼如下:
# 第一步:將原圖片通過 rb 模式讀取出來。 f = open('圖片.jpeg', mode='rb') content = f.read() f.close() # 第二步:將讀取出來的資料通過 wb 模式寫入新檔案。 f1 = open('圖片1.jpeg', mode='wb') f1.write(content) f1.close()
檔案操作的:追加
就是在檔案中追加內容。這裡也有四種檔案分類主要四種模式:a,ab,a+,a+b,我們只講a
a 模式
如果檔案不存在,利用a模式操作檔案,那麼它會先建立檔案,然後寫入內容。
f = open('追加文字', encoding='utf-8', mode='a') f.write('這個檔案是沒有的,我是新建立的') f.close()
如果檔案存在,利用a模式操作檔案,那麼它會在檔案的最後面追加內容。
f = open('追加文字', encoding='utf-8', mode='a') f.write('這是己存在的檔案,我是新追加的內容') f.close()
檔案操作的其它模式
咱們還有一種模式沒有講,就是那種帶+號的模式。什麼是帶+的模式呢?+就是加一個功能。比如剛才講的r模式是隻讀模式,在這種模式下,檔案控制代碼只能進行類似於read的這讀的操作,而不能進行write這種寫的操作。所以我們想讓這個檔案控制代碼既可以進行讀的操作,又可以進行寫的操作,那麼這個如何做呢?這就是接下來要說這樣的模式:r+ 讀寫模式,w+寫讀模式,a+寫讀模式,r+b 以bytes型別的讀寫模式.........
在這裡咱們只講一種就是r+,其他的大同小異,自己可以練練就行了。
#1. 開啟檔案的模式有(預設為文字模式):
r,只讀模式【預設模式,檔案必須存在,不存在則丟擲異常】
w,只寫模式【不可讀;不存在則建立;存在則清空內容】
a, 只追加寫模式【不可讀;不存在則建立;存在則只追加內容】
#2. 對於非文字檔案,我們只能使用b模式,"b"表示以位元組的方式操作(而所有檔案也都是以位元組的形式儲存的,使用這種模式無需考慮文字檔案的字元編碼、圖片檔案的jgp格式、視訊檔案的avi格式)
rb
wb
ab
注:以b方式開啟時,讀取到的內容是位元組型別,寫入時也需要提供位元組型別,不能指定編碼
#3,‘+’模式(就是增加了一個功能)
r+,讀寫【可讀,可寫】
w+,寫讀【可寫,可讀】
a+,寫讀【可寫,可讀】
#4,以bytes型別操作的讀寫,寫讀,寫讀模式
r+b,讀寫【可讀,可寫】
w+b,寫讀【可寫,可讀】
a+b,寫讀【可寫,可讀】
r+ 模式 讀並追加 順序不能錯
r+: 開啟一個檔案用於讀寫。檔案指標預設將會放在檔案的開頭。
f = open('檔案的讀寫.txt', encoding='utf-8', mode='r+') content = f.read() print(content) f.write('這是新寫入的內容') f.close()
注意:如果你在讀寫模式下,先寫後讀,那麼檔案就會出問題,因為預設游標是在檔案的最開始,你要是先寫,則寫入的內容會講原內容覆蓋掉,直到覆蓋到你寫完的內容,然後在後面開始讀取。
小總結:
三個大方向:
讀, 四種模式: r rb r+ r+b
寫, 四種模式 : w,wb, w+,w+b
追加 四種模式: a, ab, a+,a+b
相應的功能:
對檔案控制代碼的操作:read read(n) readline() readlines() write()
檔案操作的其它功能
f.tell() 獲取游標的位置 單位是:位元組
f = open('測試', encoding='utf-8', mode='r') print(f.tell()) content = f.read() print(f.tell()) f.close() # 原檔案內容 這是一行測試 A:這是第二行 B:這是第三行 C:這是第幾行 D:這是我也不知道第幾行 就這麼地吧. # 輸出結果: 0 # 開始的位置 122 # 結束的位置
f.seek() 調整游標的位置 (注意:移動單位是byte , 如果是utf-8的中文部分要是3的倍數)
f = open('測試', encoding='utf-8', mode='r') f.seek(9) content = f.read() print(content) f.close() # 原檔案內容 這是一行測試 A:這是第二行 B:這是第三行 C:這是第幾行 D:這是我也不知道第幾行 就這麼地吧. # 輸出結果: 行測試 A:這是第二行 B:這是第三行 C:這是第幾行 D:這是我也不知道第幾行 就這麼地吧.
f.flush() 強制重新整理
f = open('測試', encoding='utf-8', mode='w') f.write('fafdsfsfsadfsaf') f.flush() f.close()
開啟檔案的另一種方式(常用的是這種)
with open() as ....
# 優點1:不用手動關閉檔案控制代碼 # 利用with上下文管理這種方式,它會自動關閉檔案控制代碼。 with open('測試', encoding='utf-8', mode='r') as f: print(f.read()) # 優點2:可以加多個 open 操作 # 一個with 語句可以操作多個檔案,產生多個檔案控制代碼。 with open('測試', encoding='utf-8', mode='r') as f,\ open('測試', encoding='utf-8', mode='w') as f1: print(f.read()) f1.write('kckckckckckckkck')
這裡要注意一個問題,雖然使用with語句方式開啟檔案,不用你手動關閉檔案控制代碼,比較省事兒,但是依靠其自動關閉檔案控制代碼,是有一段時間的,這個時間不固定,所以這裡就會產生問題,如果你在with語句中通過r模式開啟t1檔案,那麼你在下面又以a模式開啟t1檔案,此時有可能你第二次開啟t1檔案時,第一次的檔案控制代碼還沒有關閉掉,可能就會出現錯誤,他的解決方式只能在你第二次開啟此檔案前,手動關閉上一個檔案控制代碼。
檔案的修改
檔案的資料是存放於硬碟上的,因而只存在覆蓋、不存在修改這麼一說,我們平時看到的修改檔案,都是模擬出來的效果,具體的說有兩種實現方式:
檔案操作改的流程:
1,以讀的模式開啟原檔案。
2,以寫的模式建立一個新檔案。
3,將原檔案的內容讀出來修改成新內容,寫入新檔案。
4,將原檔案刪除。
5,將新檔案重新命名成原檔案。方式一:將硬碟存放的該檔案的內容全部載入到記憶體,在記憶體中是可以修改的,修改完畢後,再由記憶體覆蓋到硬碟(word,vim,nodpad++等編輯器)
import os # 呼叫系統模組 with open('測試', encoding='utf-8') as f1,\ open('測試.bak', encoding='utf-8',mode='w') as f2: old_content = f1.read() # 全部讀入記憶體,如果檔案很大,會卡死 new_content = old_content.replace('文', 'wen') # 在記憶體中完成修改 f2.write(new_content) # 一次性寫入新檔案 os.remove('測試') # 刪除原檔案 os.rename('測試.bak', '測試') # 將新建的檔案重新命名為原檔案 # 原檔案內容 **檔案操作改的流程:** 1,以讀的模式開啟原檔案。 2,以寫的模式建立一個新檔案。 3,將原檔案的內容讀出來修改成新內容,寫入新檔案。 4,將原檔案刪除。 5,將新檔案重新命名成原檔案。 # 修改後的內容 **wen件操作改的流程:** 1,以讀的模式開啟原wen件。 2,以寫的模式建立一個新wen件。 3,將原wen件的內容讀出來修改成新內容,寫入新wen件。 4,將原wen件刪除。 5,將新wen件重新命名成原wen件。
方式二:將硬碟存放的該檔案的內容一行一行地讀入記憶體,修改完畢就寫入新檔案,最後用新檔案覆蓋原始檔(這種是常用的)
import os with open('測試', encoding='utf-8') as f1,\ open('測試.bak', encoding='utf-8',mode='w') as f2: for line in f1: # 一行一行的改,佔記憶體少 new_line = line.replace('wen', '文') f2.write(new_line) os.remove('測試') os.rename('測試.bak', '測試') # 原檔案內容 **wen件操作改的流程:** 1,以讀的模式開啟原wen件。 2,以寫的模式建立一個新wen件。 3,將原wen件的內容讀出來修改成新內容,寫入新wen件。 4,將原wen件刪除。 5,將新wen件重新命名成原wen件。 # 修改後的內容 **檔案操作改的流程:** 1,以讀的模式開啟原檔案。 2,以寫的模式建立一個新檔案。 3,將原檔案的內容讀出來修改成新內容,寫入新檔案。 4,將原檔案刪除。 5,將新檔案重新命名成原檔案。