1. 程式人生 > >Python小白學習之路(二十)—【打開文件的模式二】【文件的其他操作】

Python小白學習之路(二十)—【打開文件的模式二】【文件的其他操作】

encoding 否則 移動 換行 tar 循環 color nic true

打開文件的模式(二)

對於非文本文件,我們只能使用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 doesnt 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
b6\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小白學習之路(二十)—【打開文件的模式二】【文件的其他操作】