網站首頁 編程語言 正文
文件操作
我們可以使用python來操作文件,比如讀取文件內容、寫入新的內容等,因為任何計算機文件的本質都是一些有不同后綴的字符組成的。
python文件操作的兩種模式
打開模式
- while,寫入模式,簡寫為 w ,指定的文件不存在則創建文件,存在則打開并清空內容,并且將文件指針(光標)放在文件的開頭。
- read,讀取模式,簡寫為 r ,文件不存在則報錯,存在則打開文件,并且將文件指針放在文件的開頭。
- append,追加模式,簡寫為 a ,文件不存在則創建文件,存在則打開文件,并且將指針放在文件末尾。
- xor,異或模式,簡寫為 x ,文件存在則報錯,不存在則創建文件,將文件指針放在文件的開頭。
擴展模式
擴展模式是用來配合打開模式的輔助模式,擴展模式單獨不能使用。
- plus,增強模式,簡寫為 + ,可以讓打開模同時具有讀寫功能。
- bytes,bytes模式,簡寫為 b ,將文件按照二進制字節流編碼進行讀寫。
因此我們根據這兩種大的模式可以組合成為16種操作文件的方法。
模式 | 作用 | 模式 | 作用 |
---|---|---|---|
w | 寫入模式,只可寫,不可讀。 | a | 追加模式,只可寫,不可讀。 |
w+ | 寫入模式,可寫可讀。 | a+ | 追加模式,可寫可讀。 |
wb | 寫入模式,按照二進制字節流編碼可寫不可讀 | ab | 追加模式,按照二進制字節流可寫不可讀 |
wb+ | 寫入模式,按照二進制字節流編碼可寫可讀 | ab+ | 追加模式,按照二進制字節流可寫可讀。 |
r | 讀取模式,只可讀,不可寫。(默認模式) | x | 異或模式,只可寫,不可讀。 |
r+ | 讀取模式,可寫可讀。 | x+ | 異或模式,可寫可讀。 |
rb | 讀取模式,按照二進制字節流編碼可讀不可寫。 | xb | 異或模式,二進制字節流可寫不可讀。 |
rb+ | 讀取模式,按照二進制字節流編碼可讀可寫。 | xb+ | 異或模式,二進制字節流可寫可讀。 |
異或模式和寫入模式的區別在于,異或模式如果打開的文件在指定的路徑中如果存在,就會報錯;而寫入模式是直接打開不會報錯,但是會將源文件中的所有內容清空。因為寫入模式和讀取模式之間的互相配合,異或模式的使用頻率越來越少,正在逐步淘汰當中。
編碼格式的了解
編碼是信息從一種形式或格式轉換為另一種形式的過程,就是用預先規定的方法將文字、數字或其它對象編成數碼,或將信息、數據轉換成規定的電脈沖信號。這樣做的目的是為了簡化信息之間的傳遞。但是為保證編碼的正確性,編碼要規范化、標準化,即需有標準的編碼格式。常見的編碼格式有ASCII、ANSI、GBK、GB2312、Unicode、UTF-8等。
所有的編碼格式,都是將字符轉換成對應的二進制格式。將西方的字母文字和數字按照一個字節的方式存儲,而將亞洲中中、日、朝等文字按照多字節存儲。這是因為西方的字母語言,字母的數量遠少于東方的文字數量,因此編程工作中一般更加的傾向與盡量多的使用英文的原因,因為相對的來說使用漢字等字符較少的程序可以占據更少的系統資源。
常用的編碼格式英文原始編碼:ASCII碼
ACSII編碼只有128個字符,26個英文字母的大小寫之外,還有一些常用的符號,還有一些不可或缺的系統控制字符等。ACSII編碼中沒有除了英文字母之外的其它語言字符。
中文國家標準編碼:GB系列編碼
凡是由GB開頭的編碼集都是屬于中國國家的標準編碼字符集,只是不同的版本而已,使用這個編碼的漢字占用的系統資源最少,中文使用2個字節的存儲空間。比如GB2312。
萬國碼:Unicode編碼
Unicode編碼包含世界上所有的文字,無論什么字符都以4個字節進行存儲。這是Unicode編碼的缺點,雖然擁有世界上最齊全的字符,但是占用的系統資源很大,所以很少使用。
因此在這個基礎之上改進,創建了可變長的Unicode編碼集,UTF系列。這是目前世界上最主流的編碼字符集,在這個編碼集當中,不用擔心任何字符會亂碼,字母文字和數字使用一個字節的存儲空間,中文等字符使用三個字節的存儲空間,大大節省了空間的占用。比如UTF-8。
open函數的使用
python中操作文件要使用到open函數,open函數的作用是用于打開一個文件,創建一個file對象,使用相關的方法調用它對文件進行讀寫操作。
語法:open(file, mode=None, encoding=None)
參數說明:
- file:文件的位置和名稱
- mode:操作的模式,使用簡寫,就是我們上述的16中操作方式
- encoding:指定編碼類型,比如UTF-8、GB2312、ACSII等
open函數指定這些信息之后,返回一個TextIOWrapper對象,使用這個對象,我們可以按照指定的操作模式和編碼格式來操作我們指定的文件。
文件的寫入(寫入模式)
現在我們在使用open函數創建一個文件,并寫入內容。
可以看到我們當前的目錄當中只有一個main.py文件,我們現在寫入代碼。
# 指定文件的位置,要使用字符串,可以使用絕對路徑和相對路徑 # 操作模式的選擇,我們要創建一個新的文件并寫入內容,使用 w # 指定編碼格式為UTF-8,這是最常使用的編碼格式 # fp就是文件的IO對象,問價句柄,用來操作文件 # i --- > input 輸入 # o --- > output 輸出 fp = open('test.txt', 'w', encoding='UTF-8') # 使用write函數寫入內容 fp.write('Hello motherland') # 使用close函數關閉文件 fp.close()
執行python代碼之后,我們發現在原來的目錄下面多出了一個名為test.txt的文件。
打開這個文件我們就會發現,文件中的內容就是我們寫下的內容。
現在我們重新使用 w 模式打開這個文件,但是不操作任何東西,讓我們看看結果如何。
fp = open('test.txt', 'w', encoding='UTF-8') fp.close()
沒錯,這個文件中的內容被清空了,這就是w模式的如果文件存在,就打開文件并清空。
文件的讀取(讀取模式)
我們現在執行下面的代碼,使用 r 模式讀取文件中的內容。
# 使用 r 模式打開msr.txt文件 fp = open('msr.txt', 'r', encoding='UTF-8') # 讀取文件中的內容 res = fp.read() print(res) # 關閉文件 fp.close()
發現程序報錯了,這是為什么?因為使用 r 模式如果指定的文件不存在就會報錯。
那我們先創建一個msr.txt文件在重新讀取一下。
# 先創建一個msr.txt文件 fp = open('msr.txt', 'w', encoding='UTF-8') # 寫入內容 fp.write('劉德華太帥了。') # 關閉文件 fp.close() # 然后重新讀取這個文件 fp = open('msr.txt', 'r', encoding='UTF-8') # 讀取文件中的內容 res = fp.read() # 打印讀取的內容 print(res) # 劉德華太帥了。 # 關閉文件 fp.close()
不再報錯了,而且也成功的打印出來文件中的內容。
文件內容追加(追加模式)
追加模式如果文件不存在就創建文件,反之就打開文件,但是可寫入模式的不同之處就在于,追加模式打開文件不會清空文件中的原有的數據內容。
打開msr.txt文件,我們看到只有一行文字。
現在我們執行下面的代碼
# 使用追加模式打開文件 fp = open('msr.txt', 'a', encoding='UTF-8') # 在文件中寫入內容 fp.write('但是劉德華沒有博主帥。') # 關閉文件 fp.close()
打開文件我們看到,原有的數據并沒有被清空掉,并且寫入了新的內容。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-monzJF4R-1647692650673)(
字節流的轉換
bytes是用來傳輸或者是存儲的數據格式,如果是在文件的操作過程中按照bytes的模式操作的話,就需要將數據格式轉換成為bytes流才可以。
二進制的字節流就是底層的代碼。
使用 b 前綴
在字符串之前加上字符 b 代表是二進制的字節流,但是范圍只是ASCII編碼,也就是說這樣并不支持中文。
# 在字符串之前加上 b 前綴 bytechar = b'hello motherland' print(bytechar) # b'hello motherland' # 該字符串的數據類型就變成了bytes流 print(type(bytechar)) #bytechar = b'你好祖國' # error,只能將ACSII編碼中的字符變成bytes流
使用encode函數和decode函數可以將字符串在普通字符串和字節流的形式中來回的轉換,而且可以將所有的字符變成bytes字節流,因為默認使用UTF-8編碼,當然你也可以指定轉換的編碼格式。
函數 | 作用 |
---|---|
encode | 將字符串轉換為二進制的字節流 |
decode | 將二進制的字節流轉換為字符串 |
語法:
- string.encode(encoding='UTF-8')
- bytes.decode(encoing='UTF-8')
var = '我的祖國' # 將字符串變成字節流,默認使用UTF-8編碼 res = var.encode() print(res) # b'\xe6\x88\x91\xe7\x9a\x84\xe7\xa5\x96\xe5\x9b\xbd' print(type(res)) ## 指定編碼格式UTF-8 res = var.encode(encoding='UTF-8') print(res) # b'\xe6\x88\x91\xe7\x9a\x84\xe7\xa5\x96\xe5\x9b\xbd' # 可以看到指定為UTF-8編碼的和默認的結果是一樣的 # 指定編碼格式為ASCII res = var.encode('ASCII') # error # 因為原字符串是中文,所以不能使用ASCII編碼 # 指定為GBK編碼 res = var.encode('GBK') print(res) # b'\xce\xd2\xb5\xc4\xd7\xe6\xb9\xfa' # 可以看到GBK的編碼中文可以節省更多的空間 # 可以使用 len 函數檢測字節流的長度 print(len(res)) # 8 # 解碼 var = res.decode() # error # 應為默認使用的UTF-8解碼,但是res的編碼格式是GBK,所以失敗 # 只能使用對應的編碼格式解碼 var = res.decode('GBK') print(var) # 我的祖國
存儲二進制的字節流
如果在操作文件的時候要使用字節流的方式,在使用open函數選擇模式的時候要加上 b ,表示進行字節流的操作,然后open函數就不能在指定編碼格式了,因為現在的操作的都是字節流,然而字節流本身就已經是指定的編碼格式編碼過了。
# 如果指定了字節流模式還要指定encoding參數就會報錯 fp = open('test.txt', 'wb', encoding='UTF-8') # error # 使用字節流模式只能進行字節流的寫入 fp = open('test.txt', 'wb') # fp.write('hello motherland') # error,不能直接使用字符串 fp.write(b'hello motherland') fp.write('我的祖國'.encode()) fp.close()
寫在文件中的內容還是原來的樣子,不是字節流的形式
注意事項:
- 使用字節流模式編輯過的文件只能使用字節流模式去操作
- 使用什么格式的字節流寫入文件的內容,讀取的時候只能使用對應的編碼格式去解碼
- 任何文件都可以使用字節流模式去讀取內容,讀取的內容是字節流,如果這個文件是按照某個編碼格式寫入的,解碼需要使用對應的編碼格式;如果這個文件的內容不是使用字節流模式寫入,讀取的字節流默認是UTF-8格式的。
上下文管理器
在python中,有一些任務是當你開啟之后,結束的時候需要專門的關閉任務,比如文件操作,在結束操作的使用需要使用close()函數專門的關閉文件、結束任務,這樣就很繁瑣,所以python中推出了 with …… as ……
的語法,在 with 代碼塊中如果結束操作,不需要在專門的結束任務。
上下文管理器,任何需要進行上下文操作的對象,都可以使用此語法。
語法:with 任務 as 操作句柄:
# 不需要在使用close()函數專門的關閉文件,結束任務了 with open('test.txt', 'wb') as fp: fp.write(b'hello motherland')
刷新緩沖區
我們學習了這么久,每次都一定要關閉文件、結束任務,這樣做的意義是什么?
比較直觀的目的就是為了保存文件,但是好奇的我們早就測試了不使用close()關閉文件,寫入的內容一樣是保存了文件中的,這是怎么回事?
看下面的代碼,發現我們文件中依然是保存了我們寫入的內容。
fp = open('test.txt', 'w', encoding='UTF-8') fp.write('我和我的祖國,就像是海和浪花一朵。')
這是因為,關閉文件的根本目的是為了刷新緩沖區,然而刷新緩沖區的方法不止一種。
- 當文件關閉的時候自動刷新緩沖區
- 當整個程序運行結束的時候自動刷新緩沖區
- 當緩沖區寫滿還自動刷新緩沖區
- 手動刷新緩沖區
刷新緩沖區的意義在于最后的保存文件,就好像在使用文檔編輯器的時候,雖然寫滿內容,但最后不點擊保存按鈕內容也不會保存下來。
而我們上面的例子就是因為程序運行結束的時候自動刷新了緩沖區,所以才保存了寫入文件的內容,而close的作用就是關閉文件,關閉文件也可以刷新緩沖區,所以這就是每次要關閉文件的原因所在,為了防止自動刷新的失敗。
那么什么情況之下程序就沒有辦法執行完呢?
比如說程序的意外中斷、或者是死循環,下面的代碼中就是因為死循環的原因導致程序沒有辦法執行完成,而沒有保存新寫入的內容。
下面的代碼,先是寫入了內容,然后就是一個死循環,這樣程序永遠都不會執行完成,就不能自動的刷新緩沖區,如果程序意外中斷,內容也不會寫入文件當中,你可以將程序運行起來之后,強制中斷測試一下,會發現是一個空文件。
with open('test.txt', 'w', encoding='UTF-8') as fp: fp.write('我和我的祖國,一刻也不能分割。') while True: pass
手動刷新
上面的例子中,文件沒有辦法關閉,程序沒有辦法執行完成,貌似緩沖區也很難寫滿,難道我們的內容就沒有辦法保存了嗎?
你機智的寫上了一行代碼,是close()函數,這樣就關閉了文件,就可以將死循環之前的內容保存了嘛。
with open('test.txt', 'w', encoding='UTF-8') as fp: fp.write('我和我的祖國,一刻也不能分割。') fp.close() # 關閉文件 while True: pass
你經過測試,上面的代碼的確的保存了寫入的內容,但是我們關閉了文件,再次操作文件的時候就必須重新開啟文件,不然沒有辦法繼續操作。
with open('test.txt', 'w', encoding='UTF-8') as fp: fp.write('我和我的祖國,一刻也不能分割。') fp.close() fp.write('我和我的祖國,就像是海和浪花一朵。') # error,文件已經關閉 while True: pass
發現寫入的第二條內容根本就沒法執行了,怎么辦?使用fiush()函數手動刷新緩沖區。
with open('test.txt', 'w', encoding='UTF-8') as fp: fp.write('我和我的祖國,一刻也不能分割。') fp.flush() fp.write('我和我的祖國,就像是海和浪花一朵。') fp.flush() while True: pass
發現手動刷新將內容保存了下來,而且沒有影響程序的執行。以后如果程序任務過大,沒有執行完成就意外中斷,這樣就有一點數據保存不下來的風險,我們就可以隔著一段任務手動刷新一下,就不至于將所有的數據全部丟失。
文件的擴展模式
我們經過上面的學習,用到了寫、讀、手動刷新、關閉文件等幾種操作文件的函數,但是除此之外,還有一些常用的相關函數。
函數 | 作用 |
---|---|
write | 寫入數據 |
read | 讀取數據 |
fiush | 手動刷新緩沖區 |
close | 關閉文件 |
seek | 調整指針(光標)的位置 |
tell | 返回當前指針左側所有的字節數 |
readable | 判斷文件對象是否可讀 |
writeable | 判斷文件對象是否可寫 |
readline | 讀取文件的一行內容 |
readlines | 將文件中的內容按照換行讀取到列表當中 |
writelines | 將內容是字符串的可迭代數據寫入文件當中 |
truncate | 把要截取的字符串提取出來,然后清空內容并將截取的內容重新寫入 |
read的使用
plus增強模式的使用
在open函數中,使用 + 號,進入增強模式,可讀可寫。
我們現在使用 r+ 模式打開之前的文件,讀取其中的內容。
with open('test.txt', 'r+', encoding='UTF_8') as fp: # 讀取內容 res = fp.read() print(res) # 我和我的祖國,一刻也不能分割。我和我的祖國,就像是海和浪花一朵。 # 可以指定字符的個數,讀取指定個數的字符 res = fp.read(5) print(res) #
發現什么第二遍沒有讀取出任何的內容,我們重新打開一遍文件,重新讀取。
with open('test.txt', 'r+', encoding='UTF_8') as fp: # 讀取五個字符 res = fp.read(5) print(res) # 我和我的祖 # 再讀取五個字符 res = fp.read(5) print(res) # 國,一刻也
發現第二遍讀取的內容是接著第一遍讀取的內容之后的,我們重新打開一遍文件,寫一些內容。
with open('test.txt', 'r+', encoding='UTF_8') as fp: # 寫入內容 fp.write('我永遠和我的祖國在一起') # 讀取其中的內容 res = fp.read() print(res) # 能分割。我和我的祖國,就像是海和浪花一朵。
讀取內容的時候,發現沒有我們寫入的內容,而且讀取的文件內容怎么看起來好怪異的感覺啊,怎么少了些內容?
我們重新打開文件讀取一遍
with open('test.txt', 'r+', encoding='UTF_8') as fp: res = fp.read() print(res) # 我永遠和我的祖國在一起能分割。我和我的祖國,就像是海和浪花一朵。
為什么我們的寫入的內容在文件的開頭,而且還替換掉了原有的一部分數據?我們上面的一系列操作為什么那么的奇怪?
這都是因為光標的作用在做怪。
光標的作用
還記得我們之前介紹四種打開模式的時候嗎?寫入模式光標在文檔最后,讀取模式光標在文檔最前,追加模式光標在文檔最前,異或模式光標在文檔最前。
寫入的內容和讀取的內容都是從光標的位置開始的。
read()函數默認讀取光標一右側所有的內容。而不是文檔中的所有內容,之前的測試之所以可以一次性的讀取出所有的內容是因為我們打開文檔使用的是讀取模式,光標的位置在文檔的開頭。光標會隨著讀取的內容而移動,讀取到哪個字符光標就移動到哪個字符的后面。
write()寫入內容的時候是覆蓋模式。我們都知道我們的計算機系統中的文本輸入方式是有兩種的,使用insert鍵就可以切換著兩種模式。一種是插入模式,一種是覆蓋模式。
插入模式是我們平常最經常使用的,比如說我們打開一個文本編輯軟件,隨便的寫入一段內容,然后把光標移動到文檔的開頭,寫入內容,發現新的內容是插入到了舊的內容之前的,舊的內容不會消失,而是后移,這就是插入模式;然后重新將光標移動到文檔的開頭,然后按下insert鍵,這個時候你的輸入方式就變成了覆蓋模式,現在的你每當輸入一個新的字符就會覆蓋掉后面的一個舊字符,這就是覆蓋模式,python的文本編輯就是這種覆蓋模式。光標隨著寫入的內容向后移動。
光標位置的移動
我們剛才的時候就了解到了有一個可以調整光標位置的函數,叫做seek,使用這個函數我們可以隨意的調節光標的位置,從而編輯文件的時候可以更加的隨心所欲。
seek(offset: int, [whence: int = 0])
seek(偏移量, [基準位置])
seek函數的兩個參數都是整型。
第一個參數表示的是偏移量,單獨使用時表示將光標移動到從文檔的開頭算起的第N個字節的位置后;
第二個參數表示的光標的位置,使用的時候只有0、1、2三個選型,且偏移量必須為0;
0代表的是文檔的最開端
1代表的是光標的當前位置
2代表的是文檔的最后端
# 先使用 w+ 模式打開一個文件,這個時候的文件為空,光標在文檔的開頭位置 with open('test.txt', 'w+', encoding='UTF-8') as fp: # 我們寫入內容,這個時候光標的位置隨著寫入的內容到了文檔的最后 fp.write('hello motherland.') # 所以現在的光標的右側沒有任何一個字節符,所以讀不出任何的內容 res = fp.read() print(repr(res)) # '' # 所以光標還是在最后的位置,使用seek切換光標的位置為開頭,讀取剛才寫入的內容 fp.seek(0) res = fp.read() print(repr(res)) # 'hello motherland.' # 讀取完內容之后,光標又到了文檔的最后的位置,調整到開頭的第五個字節符的位置 fp.seek(5) # 再次讀取文件的內容,這一次只讀取5個字符,發現前五個字符沒有了 res = fp.read(5) print(repr(res)) # ' moth' # 現在光標在文檔的第十個字符位置,我們將光標切換到文檔的最后,然后讀取文檔發現什么內容也沒有 fp.seek(0, 2) res = fp.read() print(repr(res)) # ''
注意到了嗎?我說的seek移動的是字節的數量,什么是字節的數量?
我們之前說的不同的編碼格式對于不同的字符都是不一樣的,但是所有的編碼格式對于英文字母為主的一些的字符都是一個字節的大小,但是漢字不一樣,漢字在GB中是兩個字節、UTF中是三個字節、Unicode中是四個字節。
seek的偏移單位是字節,不是字符,所以在使用seek在操作bytes字節流時,要注意移動的間隔,因為移動的是字節位數,而在GB編碼中一個漢字兩個字節,在Unicode(UTF-8)中,一個漢字三個字節,如果seek將指針移動至漢字之間,就會導致讀取時漢字的編碼不完整而導致錯誤。
# 重新寫入一個文件,注意我們的編碼格式 with open('test.txt', 'w+', encoding='UTF-8') as fp: fp.write('我和我的祖國,一刻也不能分割。我和我的祖國,就像是海和浪花一朵。') # 我們現在讀取除了第一句話之后的內容,前面的內容一共是15個字符,我們使用seek跳過去 fp.seek(15) res = fp.read() print(repr(res)) # '國,一刻也不能分割。我和我的祖國,就像是海和浪花一朵。' # 咦?怎么只跳過了五個漢字?因為我們使用的UTF-8的編碼,一個漢字由3個字節,真好是15個單位 # 你是幸運的,如果我們在右移一個字節的單位,就是一個漢字都沒有完全遷移完會怎么樣? fp.seek(1) # res = fp.read() # print(res) # error, 報錯了,因為剩下的字符不是完整的,所以沒有辦法讀出,就報錯了
# 就像是你好的UTF-8編碼是六個字節組成的, print('你好'.encode()) # b'\xe4\xbd\xa0\xe5\xa5\xbd' # 如果去掉了一個字節,就是不完整的了,還能解碼出來嗎? print(b'\xbd\xa0\xe5\xa5\xbd'.decode()) # error,解碼失敗
所以在使用seek函數的時候一定要慎用。
tell的使用
# tell 當前光標左側所有的字節數(返回字節數) # 使用閱讀模式打開文件 with open('test.txt', 'r+', encoding='UTF-8') as fp: # 使用tell函數查看貫標左側的字節數 res = fp.tell() print(res) # 0 # 因為閱讀模式的光標在文件的開頭,所以返回0個字節數 # 使用seek將光標移動到文檔的末尾 fp.seek(0, 2) # 使用tell查看整個文檔的字節數,這就是文檔的大小 res = fp.tell() print(res) # 96 # 快去看看你的文件信息中的文件大小是不是96字節的?
其它的相關函數
判斷文件對象可讀可寫
# 使用 r+ 模式打開文件 with open('test.txt', 'r+', encoding='UTF-8') as fp: # 使用readable 和 readable 查看這個文檔是否可讀可寫 if fp.readable(): print('本文檔可讀') if fp.writable(): print('本文檔可寫') ''' 結果: 本文檔可讀 本文檔可寫 '''
readline
讀取一行內容
# 打開文件,重新寫入多行內容 with open('test.txt', 'w+', encoding='UTF-8') as fp: # 可以使用多行字符串 fp.write('''11111 22222 33333 ''') # 也可以使用轉義字符進行換行 fp.write('44444\n55555\n66666')
with open('test.txt', 'r+', encoding='UTF-8') as fp: # 使用read讀取的整個文檔的內容 res = fp.read() print(res) ''' 結果: 11111 22222 33333 44444 55555 66666 ''' # 使用readline讀取一一行的內容 fp.seek(0) res = fp.readline() print(res) # 11111 # 再讀取一行 res = fp.readline() print(res) # 22222 # 可以指定讀取的字符個數 res = fp.readline(3) print(res) # 333 # 如果指定的個數大于本行的字符個數,就讀取本行所有的內容 res = fp.readline(1000) print(res) # 33 # 為什么是33不是44444?因為readline也要受到光標的影響
readlines
將文件中的內容按照換行讀取到列表中
with open('test.txt', 'r+', encoding='UTF-8') as fp: res = fp.readlines() print(res) # ['11111\n', '22222\n', '33333\n', '44444\n', '55555\n', '66666'
注意:readlines不會影響光標的移動,但是讀取的是光標的右側數據;而且readlines的讀取將換行符也讀取上了,因為換行符本身也是一行的內容。
按行讀取內容我一般使用到readlines
函數,但是也可以使用其它的方法,比如直接遍歷open
實例化對象,open
實例化對象本身就是一個可迭代對象,它將文件中的內容按照換行符分開。
with open('text.txt', 'r', encoding='UTF-8') as fp: for line in fp: print(line)
writelines
將內容是字符串的可迭代性數據寫入文件中,writelines不會根據元素換行。
lst = ['china', 'america', 'russia'] with open('test.txt', 'w+', encoding='UTF-8') as fp: # 使用writelines寫入內容 fp.writelines(lst) fp.seek(0) # 讀取數據 res = fp.readlines() print(res) # ['chinaamericarussia']
truncate
文件中的內容只保留截取的內容。
從文件開頭開始,截取指定字節長度的內容,然后將文件清空,然后將截取的內容重新填入文件中。
# 打開一個文件 with open('test.txt', 'w+', encoding='UTF-8') as fp: # 寫入一段內容 fp.write('1234567890') # 保留截取的內容,只保留前5個字節的內容 fp.truncate(5) # 查看文件的內容 fp.seek(0) res = fp.read() print(res) # 12345
關于生成文件MD5心得
我在工作時需要給調用翻譯狗的一個API,用于上傳文獻并翻譯返回,但是對方需要文件MD5進行驗證,我們需要在接入接口的時候,需要將文件md5傳入,這個時候就出現了一些問題,我在傳入文件和文件MD5的時候,被對方回應文件MD5
不匹配,我很好奇,為什么會出現這樣的情況?
我在使用這個接口當中,有好幾處地方比如token的生成和文件md5的地方都會需要md5加密,所以為此我們專門將生成md5的代碼封裝成為一個函數(將字符串輸入,返回md5,代碼如下:
import hashlib def enMD5(target): """ MD5加密 """ res = hashlib.md5(target.encode()).hexdigest() return res
python中生成md5需要輸入字節流格式的數據,而我一開始只有字符串的數據需要使用md5加密,所以我在函數中將字符串變成字節流。token就是傳入字符串得到的。
但是文件md5的話可以直接讀出字節流的格式,但是因為再使用這個函數不方便,所以我使用正常讀取文檔的方式讀取文件中的內容,然后放入函數中,結果就是上面說的,和對方得出的文件md5并不匹配。我自認為我的代碼是沒有問題的,于是我們依次查找問題的所在,后來我發現網上很多博主的方法都是直接從文件讀取二進制字節流的方式獲取的,我實在是沒有辦法了,就想會不會就是讀取方式的問題呢?果然,我就發現不同格式讀取的出來的結果是不同的,測試的案例如下:
with open(file_path, 'w', encoding='UTF-8') as fp: fp.write('msr\nhello\r\nmotherland.') with open(file_path, 'rb') as fp: print(fp.read()) with open(file_path, 'r', encoding='UTF-8') as fp: print(r'f', repr(fp.read()), sep='')
上述的結果為:
b'msr\r\nhello\r\r\nmotherland.'
f'msr\nhello\n\nmotherland.'
沒錯,我發現直接使用b
模式和普通模式讀取內容然后轉化成為bytes
的結果是不同的,那么也必將導致最后文件md5是不正確的。大家也看到了,不管是哪一種讀取的方法其實和我寫入的內容都是不同的,在本次的測試案例當中對于換行有著不同的認知,讀取的原因我沒有深入了解,但是我注意到了官方文檔中說b
模式就是專門讀取文件字節流格式的,所以以后大家生成文件md5的時候,一定要直接使用b
模式讀取文件內容。
上述的測試環境是:
python: python3.6.8_win_x64(Cpython)
system: windows_10_x64
原文鏈接:https://www.cnblogs.com/msr20666/p/16027850.html
相關推薦
- 2022-05-26 Pytorch中使用ImageFolder讀取數據集時忽略特定文件_python
- 2022-07-10 jQuery表格添加數據并Ajax提交數據
- 2022-05-12 小程序滾動穿透解決方案
- 2022-09-01 ASP.NET?Core通用主機實現托管服務_實用技巧
- 2023-03-22 Redis慢查詢日志及慢查詢分析詳解_Redis
- 2022-05-25 swagger 3.0.0 版本和springboot整合啟動失敗
- 2022-10-12 使用Docker搭建Vsftpd?的?FTP?服務的詳細過程_docker
- 2022-07-04 Python迭代器的實現原理_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支