Python小白學習之路(二十)—【打開文件的模式二】【文件的其他操作】
打開文件的模式(二)
對於非文本文件,我們只能使用b模式,"b"表示以字節的方式操作
(而所有文件也都是以字節的形式存儲的,使用這種模式無需考慮文本文件的字符編碼、圖片文件的jgp格式、視頻文件的avi格式)
rb: 以字節方式讀文件
wb: 以字節方式寫文件
ab: 以字節方式追加文件
註:以b方式打開時,讀取到的內容是字節類型,寫入時也需要提供字節類型,所以不能指定編碼
1. rb
#錯誤舉例 f = open (‘test1.py‘, ‘rb‘, encoding = ‘utf -8‘) data = f.read() print(data) f.close() #執行結果:報錯 f = open (‘test1.py‘, ‘rb‘, encoding = ‘utf-8‘) ValueError: binary mode doesn‘t take an encoding argument
(以b方式打開時,因為讀取到的內容是字節類型,所以不能指定編碼方式,否則會報錯)
#正確 f = open (‘test1.py‘, ‘rb‘) data = f.read() print(data) f.close() #執行結果: b"‘hello‘\r\n‘\xe5\xb0\x8f\xe7\x81\xab\xe9\x94\x85‘\r\n‘666‘"
test1.py中的內容如下:
‘hello‘
‘小火鍋‘
‘666‘
分析該程序執行結果:
1. python在windows操作系統下,換行符為在windows操作系統下,換行符為 \r\n
2. ‘字符串’-------encode-------》bytes
bytes---------decode-------》‘字符串’
所以,我們想讓執行結果為字符串,可在print時做decode處理
f = open (‘test1.py‘, ‘rb‘) data = f.read() print(data.decode(‘utf-8‘)) f.close() #執行結果: ‘hello‘ ‘小火鍋‘ ‘666‘
2. wb
#錯誤舉例 f = open (‘test1.py‘, ‘wb‘) f.write(‘hello‘) f.close() #執行結果: TypeError: a bytes-like object is required, not ‘str‘ (以b方式寫入時需要提供字節類型,所以不能寫入字符串類型)
#正確 f = open (‘test1.py‘, ‘wb‘) f.write(bytes(‘hello\n小火鍋‘, encoding = ‘utf-8‘ )) f.close()
3. ab
#舉例 f = open (‘test1.py‘, ‘ab‘) f.write(bytes(‘hello\n小火鍋\n‘, encoding = ‘utf-8‘ )) f.close()
關於文件的其他操作介紹
1. .encoding 讀取文件打開時後的編碼方式(即open時指定的編碼方式)
#舉例 f = open (‘test1.py‘, ‘w‘, encoding = ‘GB2312‘) f.close() print(f.encoding) #執行結果: GB2312
2. .closed 確定文件是否關閉
#舉例 f = open (‘test1.py‘, ‘w‘, encoding = ‘utf-8‘) f.close() print(f.closed) #執行結果: True
3. .flush 刷新操作(將文件內容從內存刷到硬盤)
4. .tell 讀取光標所在位置
補充:文件內光標移動
一: read(3):
1. 文件打開方式為文本模式時,代表讀取3個字符
2. 文件打開方式為b模式時,代表讀取3個字節
二: 其余的文件內光標移動都是以字節為單位如seek,tell,truncate
test1中的內容
aaa
小火鍋
666
#舉例 f = open (‘test1.py‘, ‘r‘, encoding = ‘utf-8‘) print(f.tell()) f.readline() print(f.tell()) f.readline() print(f.tell()) f.close() #執行結果: 0 5 16
#結果分析: 第一個tell判斷光標位置時候,光標在文件開頭,即在位置0 讀取了一行之後,光標跑到文件第二行開頭,但是在Windows操作系統,換行符為 \r\n,占兩個字節,而且tell光標移動以字節為單位,所以光標位置為 5 讀取了第二行之後,光標跑到了文件第三行開頭,光標經歷了三個漢字和換行符,在編碼方式為 utf-8 時,走過了3*3+2=11個字節,所以光標位置為 16
5. .seek 控制光標的移動
#舉例 f = open (‘test1.py‘, ‘r‘, encoding = ‘utf-8‘) f.seek(2) #光標從默認位置0開始,往後移動兩個字節 data = f.read() print(data) #打印光標後的內容 f.close() #執行結果: a 小火鍋 666
如果,我將test1.py的內容改為
小火鍋
aaa
666
再次執行上述程序
#報錯:UnicodeDecodeError: ‘utf-8‘ codec can‘t decode byte 0x8f in position 0: invalid start byte
原因:一個漢字在utf-8編碼方式為3個字節,seek(2)移動兩個字節,難道有神奇的功能將漢字劈開嘛,所以肯定會報錯啊!
關於seek的一些補充:
seek有三種模式,分別為
- 0模式 默認從0開始(不用指定)
- 1模式 從上次相對位置開始
- 2模式 從文件末尾開始seek(第一個參數需要為負數)
舉例: f = open (‘test1.py‘, ‘r‘, encoding = ‘utf-8‘) f.seek(3) print(f.tell()) f.seek(9) print(f.tell()) f.close() #執行結果 3 9
f = open (‘test1.py‘, ‘rb‘) f.seek(3,1) print(f.tell()) f.seek(10,1) print(f.tell()) f.close() #執行結果 3 13
f = open (‘test1.py‘, ‘rb‘) f.seek(-3,2) #seek 在模式 2 時,第一個參數為負數 print(f.tell()) print(f.read()) f.close() #執行結果 18 b‘6\r\n‘
任務:應用:打開一個日誌文件,並且讀取最新日誌(核心:倒著讀文件內容)
日誌文件內容如下:
2018/11/20 aaa 上網聽歌
2018/11/20 bbb 上網網購
2018/11/20 ccc 上網學習
#方法一 f = open(‘日誌文件‘, ‘rb‘) data = f.readlines() #將日誌文件的內容以列表形式讀到內存中 print(data[-1].decode(‘utf-8‘)) #以切片方式讀取列表中最後一個元素,即文件最後一行內容 #執行結果 2018/11/20 ccc 上網學習
#方法二 f = open(‘日誌文件‘, ‘rb‘) for i in f: #文件循環方式 offs = -10 #設置初始偏移量 while True: #設置一個死循環來讀取文件的最後一行內容,讀取到break f.seek(offs, 2) #seek模式2,光標倒著移動 data = f.readlines() #以列表形式讀取光標後的內容 if len(data) > 1: #如果該列表長度大於1,說明光標移動到最後一行之前,最後一行內容已被讀出,break,反則最後一行內容還未全部讀出,將偏移量擴大,直到獨處最後一行全部內容 print(‘文件最後一行:%s‘%(data[-1].decode(‘utf-8‘))) break offs *= 2 #執行結果 文件最後一行:2018/11/20 ccc 上網學習
方法一看著簡單,但是方法一需要將日誌文件的內容一列表形式全部讀到內存中,占用較多內存
方法二的思想就是我用最後一行內容,我倒著讀,只關註我想得到的信息
6. .truncate 截取文件內容(實質為文件內容的改寫,所以在 open 文件時,需要設置正確的打開文件的模式)
舉例: f = open(‘日誌文件‘, ‘r+‘,encoding = ‘utf-8‘) data = f.truncate(8) print(data)
註意:
- 打開方式不可以是r(報錯,實質為文件的改寫)
- 打開方式不可以是w w+(這兩個模式將內容全部刪除,所以截取不到任何內容)
Python小白學習之路(二十)—【打開文件的模式二】【文件的其他操作】