欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python?IO文件管理的具體使用

 更新時(shí)間:2022年03月20日 09:49:47   作者:小小垂髫  
我們可以使用python來(lái)操作文件,比如讀取文件內(nèi)容、寫入新的內(nèi)容等,本文主要介紹了Python?IO文件管理的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

文件操作

我們可以使用python來(lái)操作文件,比如讀取文件內(nèi)容、寫入新的內(nèi)容等,因?yàn)槿魏斡?jì)算機(jī)文件的本質(zhì)都是一些有不同后綴的字符組成的。

python文件操作的兩種模式

打開(kāi)模式

  • while,寫入模式,簡(jiǎn)寫為 w ,指定的文件不存在則創(chuàng)建文件,存在則打開(kāi)并清空內(nèi)容,并且將文件指針(光標(biāo))放在文件的開(kāi)頭。
  • read,讀取模式,簡(jiǎn)寫為 r ,文件不存在則報(bào)錯(cuò),存在則打開(kāi)文件,并且將文件指針?lè)旁谖募拈_(kāi)頭。
  • append,追加模式,簡(jiǎn)寫為 a ,文件不存在則創(chuàng)建文件,存在則打開(kāi)文件,并且將指針?lè)旁谖募┪病?/li>
  • xor,異或模式,簡(jiǎn)寫為 x ,文件存在則報(bào)錯(cuò),不存在則創(chuàng)建文件,將文件指針?lè)旁谖募拈_(kāi)頭。

擴(kuò)展模式

擴(kuò)展模式是用來(lái)配合打開(kāi)模式的輔助模式,擴(kuò)展模式單獨(dú)不能使用。

  • plus,增強(qiáng)模式,簡(jiǎn)寫為 + ,可以讓打開(kāi)模同時(shí)具有讀寫功能。
  • bytes,bytes模式,簡(jiǎn)寫為 b ,將文件按照二進(jìn)制字節(jié)流編碼進(jìn)行讀寫。

因此我們根據(jù)這兩種大的模式可以組合成為16種操作文件的方法。

模式作用模式作用
w寫入模式,只可寫,不可讀。a追加模式,只可寫,不可讀。
w+寫入模式,可寫可讀。a+追加模式,可寫可讀。
wb寫入模式,按照二進(jìn)制字節(jié)流編碼可寫不可讀ab追加模式,按照二進(jìn)制字節(jié)流可寫不可讀
wb+寫入模式,按照二進(jìn)制字節(jié)流編碼可寫可讀ab+追加模式,按照二進(jìn)制字節(jié)流可寫可讀。
r讀取模式,只可讀,不可寫。(默認(rèn)模式)x異或模式,只可寫,不可讀。
r+讀取模式,可寫可讀。x+異或模式,可寫可讀。
rb讀取模式,按照二進(jìn)制字節(jié)流編碼可讀不可寫。xb異或模式,二進(jìn)制字節(jié)流可寫不可讀。
rb+讀取模式,按照二進(jìn)制字節(jié)流編碼可讀可寫。xb+異或模式,二進(jìn)制字節(jié)流可寫可讀。

異或模式和寫入模式的區(qū)別在于,異或模式如果打開(kāi)的文件在指定的路徑中如果存在,就會(huì)報(bào)錯(cuò);而寫入模式是直接打開(kāi)不會(huì)報(bào)錯(cuò),但是會(huì)將源文件中的所有內(nèi)容清空。因?yàn)閷懭肽J胶妥x取模式之間的互相配合,異或模式的使用頻率越來(lái)越少,正在逐步淘汰當(dāng)中。

編碼格式的了解

編碼是信息從一種形式或格式轉(zhuǎn)換為另一種形式的過(guò)程,就是用預(yù)先規(guī)定的方法將文字、數(shù)字或其它對(duì)象編成數(shù)碼,或?qū)⑿畔ⅰ?shù)據(jù)轉(zhuǎn)換成規(guī)定的電脈沖信號(hào)。這樣做的目的是為了簡(jiǎn)化信息之間的傳遞。但是為保證編碼的正確性,編碼要規(guī)范化、標(biāo)準(zhǔn)化,即需有標(biāo)準(zhǔn)的編碼格式。常見(jiàn)的編碼格式有ASCII、ANSI、GBK、GB2312、Unicode、UTF-8等。

所有的編碼格式,都是將字符轉(zhuǎn)換成對(duì)應(yīng)的二進(jìn)制格式。將西方的字母文字和數(shù)字按照一個(gè)字節(jié)的方式存儲(chǔ),而將亞洲中中、日、朝等文字按照多字節(jié)存儲(chǔ)。這是因?yàn)槲鞣降淖帜刚Z(yǔ)言,字母的數(shù)量遠(yuǎn)少于東方的文字?jǐn)?shù)量,因此編程工作中一般更加的傾向與盡量多的使用英文的原因,因?yàn)橄鄬?duì)的來(lái)說(shuō)使用漢字等字符較少的程序可以占據(jù)更少的系統(tǒng)資源。

常用的編碼格式英文原始編碼:ASCII碼

ACSII編碼只有128個(gè)字符,26個(gè)英文字母的大小寫之外,還有一些常用的符號(hào),還有一些不可或缺的系統(tǒng)控制字符等。ACSII編碼中沒(méi)有除了英文字母之外的其它語(yǔ)言字符。

中文國(guó)家標(biāo)準(zhǔn)編碼:GB系列編碼

凡是由GB開(kāi)頭的編碼集都是屬于中國(guó)國(guó)家的標(biāo)準(zhǔn)編碼字符集,只是不同的版本而已,使用這個(gè)編碼的漢字占用的系統(tǒng)資源最少,中文使用2個(gè)字節(jié)的存儲(chǔ)空間。比如GB2312。

萬(wàn)國(guó)碼:Unicode編碼

Unicode編碼包含世界上所有的文字,無(wú)論什么字符都以4個(gè)字節(jié)進(jìn)行存儲(chǔ)。這是Unicode編碼的缺點(diǎn),雖然擁有世界上最齊全的字符,但是占用的系統(tǒng)資源很大,所以很少使用。

因此在這個(gè)基礎(chǔ)之上改進(jìn),創(chuàng)建了可變長(zhǎng)的Unicode編碼集,UTF系列。這是目前世界上最主流的編碼字符集,在這個(gè)編碼集當(dāng)中,不用擔(dān)心任何字符會(huì)亂碼,字母文字和數(shù)字使用一個(gè)字節(jié)的存儲(chǔ)空間,中文等字符使用三個(gè)字節(jié)的存儲(chǔ)空間,大大節(jié)省了空間的占用。比如UTF-8。

open函數(shù)的使用

python中操作文件要使用到open函數(shù),open函數(shù)的作用是用于打開(kāi)一個(gè)文件,創(chuàng)建一個(gè)file對(duì)象,使用相關(guān)的方法調(diào)用它對(duì)文件進(jìn)行讀寫操作。

語(yǔ)法:open(file, mode=None, encoding=None)

參數(shù)說(shuō)明:

  • file:文件的位置和名稱
  • mode:操作的模式,使用簡(jiǎn)寫,就是我們上述的16中操作方式
  • encoding:指定編碼類型,比如UTF-8、GB2312、ACSII等

open函數(shù)指定這些信息之后,返回一個(gè)TextIOWrapper對(duì)象,使用這個(gè)對(duì)象,我們可以按照指定的操作模式和編碼格式來(lái)操作我們指定的文件。

文件的寫入(寫入模式)

現(xiàn)在我們?cè)谑褂胦pen函數(shù)創(chuàng)建一個(gè)文件,并寫入內(nèi)容。

可以看到我們當(dāng)前的目錄當(dāng)中只有一個(gè)main.py文件,我們現(xiàn)在寫入代碼。

# 指定文件的位置,要使用字符串,可以使用絕對(duì)路徑和相對(duì)路徑
# 操作模式的選擇,我們要?jiǎng)?chuàng)建一個(gè)新的文件并寫入內(nèi)容,使用 w
# 指定編碼格式為UTF-8,這是最常使用的編碼格式

# fp就是文件的IO對(duì)象,問(wèn)價(jià)句柄,用來(lái)操作文件
# i --- >   input  輸入
# o --- >   output 輸出
fp = open('test.txt', 'w', encoding='UTF-8')

# 使用write函數(shù)寫入內(nèi)容
fp.write('Hello motherland')

# 使用close函數(shù)關(guān)閉文件
fp.close()

執(zhí)行python代碼之后,我們發(fā)現(xiàn)在原來(lái)的目錄下面多出了一個(gè)名為test.txt的文件。

打開(kāi)這個(gè)文件我們就會(huì)發(fā)現(xiàn),文件中的內(nèi)容就是我們寫下的內(nèi)容。

現(xiàn)在我們重新使用 w 模式打開(kāi)這個(gè)文件,但是不操作任何東西,讓我們看看結(jié)果如何。

fp = open('test.txt', 'w', encoding='UTF-8')
fp.close()

沒(méi)錯(cuò),這個(gè)文件中的內(nèi)容被清空了,這就是w模式的如果文件存在,就打開(kāi)文件并清空。

文件的讀取(讀取模式)

我們現(xiàn)在執(zhí)行下面的代碼,使用 r 模式讀取文件中的內(nèi)容。

# 使用 r 模式打開(kāi)msr.txt文件
fp = open('msr.txt', 'r', encoding='UTF-8')

# 讀取文件中的內(nèi)容
res = fp.read()
print(res)

# 關(guān)閉文件
fp.close()

發(fā)現(xiàn)程序報(bào)錯(cuò)了,這是為什么?因?yàn)槭褂?r 模式如果指定的文件不存在就會(huì)報(bào)錯(cuò)。

那我們先創(chuàng)建一個(gè)msr.txt文件在重新讀取一下。

# 先創(chuàng)建一個(gè)msr.txt文件
fp = open('msr.txt', 'w', encoding='UTF-8')
# 寫入內(nèi)容
fp.write('劉德華太帥了。')
# 關(guān)閉文件
fp.close()


# 然后重新讀取這個(gè)文件
fp = open('msr.txt', 'r', encoding='UTF-8')

# 讀取文件中的內(nèi)容
res = fp.read()

# 打印讀取的內(nèi)容
print(res)   # 劉德華太帥了。

# 關(guān)閉文件
fp.close()

不再報(bào)錯(cuò)了,而且也成功的打印出來(lái)文件中的內(nèi)容。

文件內(nèi)容追加(追加模式)

追加模式如果文件不存在就創(chuàng)建文件,反之就打開(kāi)文件,但是可寫入模式的不同之處就在于,追加模式打開(kāi)文件不會(huì)清空文件中的原有的數(shù)據(jù)內(nèi)容。

打開(kāi)msr.txt文件,我們看到只有一行文字。

現(xiàn)在我們執(zhí)行下面的代碼

# 使用追加模式打開(kāi)文件
fp = open('msr.txt', 'a', encoding='UTF-8')

# 在文件中寫入內(nèi)容
fp.write('但是劉德華沒(méi)有博主帥。')

# 關(guān)閉文件
fp.close()

打開(kāi)文件我們看到,原有的數(shù)據(jù)并沒(méi)有被清空掉,并且寫入了新的內(nèi)容。

[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-monzJF4R-1647692650673)(

字節(jié)流的轉(zhuǎn)換

bytes是用來(lái)傳輸或者是存儲(chǔ)的數(shù)據(jù)格式,如果是在文件的操作過(guò)程中按照bytes的模式操作的話,就需要將數(shù)據(jù)格式轉(zhuǎn)換成為bytes流才可以。

二進(jìn)制的字節(jié)流就是底層的代碼。

使用 b 前綴

在字符串之前加上字符 b 代表是二進(jìn)制的字節(jié)流,但是范圍只是ASCII編碼,也就是說(shuō)這樣并不支持中文。

# 在字符串之前加上 b 前綴
bytechar = b'hello motherland'

print(bytechar)  # b'hello motherland'
# 該字符串的數(shù)據(jù)類型就變成了bytes流
print(type(bytechar))   # <class 'bytes'>

bytechar = b'你好祖國(guó)'	# error,只能將ACSII編碼中的字符變成bytes流

使用encode函數(shù)和decode函數(shù)可以將字符串在普通字符串和字節(jié)流的形式中來(lái)回的轉(zhuǎn)換,而且可以將所有的字符變成bytes字節(jié)流,因?yàn)槟J(rèn)使用UTF-8編碼,當(dāng)然你也可以指定轉(zhuǎn)換的編碼格式。

函數(shù)作用
encode將字符串轉(zhuǎn)換為二進(jìn)制的字節(jié)流
decode將二進(jìn)制的字節(jié)流轉(zhuǎn)換為字符串

語(yǔ)法:

  • string.encode(encoding='UTF-8')
  • bytes.decode(encoing='UTF-8')
var = '我的祖國(guó)'

# 將字符串變成字節(jié)流,默認(rèn)使用UTF-8編碼
res = var.encode()
print(res)  # b'\xe6\x88\x91\xe7\x9a\x84\xe7\xa5\x96\xe5\x9b\xbd'
print(type(res))    # <class 'bytes'>


# 指定編碼格式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編碼的和默認(rèn)的結(jié)果是一樣的


# 指定編碼格式為ASCII
res = var.encode('ASCII')	# error
# 因?yàn)樵址侵形?,所以不能使用ASCII編碼


# 指定為GBK編碼
res = var.encode('GBK')
print(res)  # b'\xce\xd2\xb5\xc4\xd7\xe6\xb9\xfa'
# 可以看到GBK的編碼中文可以節(jié)省更多的空間


# 可以使用 len 函數(shù)檢測(cè)字節(jié)流的長(zhǎng)度
print(len(res))	# 8


# 解碼
var = res.decode()  # error
# 應(yīng)為默認(rèn)使用的UTF-8解碼,但是res的編碼格式是GBK,所以失敗


# 只能使用對(duì)應(yīng)的編碼格式解碼
var = res.decode('GBK')
print(var)  # 我的祖國(guó)

存儲(chǔ)二進(jìn)制的字節(jié)流

如果在操作文件的時(shí)候要使用字節(jié)流的方式,在使用open函數(shù)選擇模式的時(shí)候要加上 b ,表示進(jìn)行字節(jié)流的操作,然后open函數(shù)就不能在指定編碼格式了,因?yàn)楝F(xiàn)在的操作的都是字節(jié)流,然而字節(jié)流本身就已經(jīng)是指定的編碼格式編碼過(guò)了。

# 如果指定了字節(jié)流模式還要指定encoding參數(shù)就會(huì)報(bào)錯(cuò)
fp = open('test.txt', 'wb', encoding='UTF-8')   # error


# 使用字節(jié)流模式只能進(jìn)行字節(jié)流的寫入
fp = open('test.txt', 'wb')
# fp.write('hello motherland')    # error,不能直接使用字符串
fp.write(b'hello motherland')
fp.write('我的祖國(guó)'.encode())
fp.close()

寫在文件中的內(nèi)容還是原來(lái)的樣子,不是字節(jié)流的形式

注意事項(xiàng):

  • 使用字節(jié)流模式編輯過(guò)的文件只能使用字節(jié)流模式去操作
  • 使用什么格式的字節(jié)流寫入文件的內(nèi)容,讀取的時(shí)候只能使用對(duì)應(yīng)的編碼格式去解碼
  • 任何文件都可以使用字節(jié)流模式去讀取內(nèi)容,讀取的內(nèi)容是字節(jié)流,如果這個(gè)文件是按照某個(gè)編碼格式寫入的,解碼需要使用對(duì)應(yīng)的編碼格式;如果這個(gè)文件的內(nèi)容不是使用字節(jié)流模式寫入,讀取的字節(jié)流默認(rèn)是UTF-8格式的。

上下文管理器

在python中,有一些任務(wù)是當(dāng)你開(kāi)啟之后,結(jié)束的時(shí)候需要專門的關(guān)閉任務(wù),比如文件操作,在結(jié)束操作的使用需要使用close()函數(shù)專門的關(guān)閉文件、結(jié)束任務(wù),這樣就很繁瑣,所以python中推出了 with …… as ……的語(yǔ)法,在 with 代碼塊中如果結(jié)束操作,不需要在專門的結(jié)束任務(wù)。

上下文管理器,任何需要進(jìn)行上下文操作的對(duì)象,都可以使用此語(yǔ)法。

語(yǔ)法:with 任務(wù) as 操作句柄:

# 不需要在使用close()函數(shù)專門的關(guān)閉文件,結(jié)束任務(wù)了
with open('test.txt', 'wb') as fp:
	fp.write(b'hello motherland')

刷新緩沖區(qū)

我們學(xué)習(xí)了這么久,每次都一定要關(guān)閉文件、結(jié)束任務(wù),這樣做的意義是什么?

比較直觀的目的就是為了保存文件,但是好奇的我們?cè)缇蜏y(cè)試了不使用close()關(guān)閉文件,寫入的內(nèi)容一樣是保存了文件中的,這是怎么回事?

看下面的代碼,發(fā)現(xiàn)我們文件中依然是保存了我們寫入的內(nèi)容。

fp = open('test.txt', 'w', encoding='UTF-8')
fp.write('我和我的祖國(guó),就像是海和浪花一朵。')

這是因?yàn)?,關(guān)閉文件的根本目的是為了刷新緩沖區(qū),然而刷新緩沖區(qū)的方法不止一種。

  • 當(dāng)文件關(guān)閉的時(shí)候自動(dòng)刷新緩沖區(qū)
  • 當(dāng)整個(gè)程序運(yùn)行結(jié)束的時(shí)候自動(dòng)刷新緩沖區(qū)
  • 當(dāng)緩沖區(qū)寫滿還自動(dòng)刷新緩沖區(qū)
  • 手動(dòng)刷新緩沖區(qū)

刷新緩沖區(qū)的意義在于最后的保存文件,就好像在使用文檔編輯器的時(shí)候,雖然寫滿內(nèi)容,但最后不點(diǎn)擊保存按鈕內(nèi)容也不會(huì)保存下來(lái)。

而我們上面的例子就是因?yàn)槌绦蜻\(yùn)行結(jié)束的時(shí)候自動(dòng)刷新了緩沖區(qū),所以才保存了寫入文件的內(nèi)容,而close的作用就是關(guān)閉文件,關(guān)閉文件也可以刷新緩沖區(qū),所以這就是每次要關(guān)閉文件的原因所在,為了防止自動(dòng)刷新的失敗。

那么什么情況之下程序就沒(méi)有辦法執(zhí)行完呢?

比如說(shuō)程序的意外中斷、或者是死循環(huán),下面的代碼中就是因?yàn)樗姥h(huán)的原因?qū)е鲁绦驔](méi)有辦法執(zhí)行完成,而沒(méi)有保存新寫入的內(nèi)容。

下面的代碼,先是寫入了內(nèi)容,然后就是一個(gè)死循環(huán),這樣程序永遠(yuǎn)都不會(huì)執(zhí)行完成,就不能自動(dòng)的刷新緩沖區(qū),如果程序意外中斷,內(nèi)容也不會(huì)寫入文件當(dāng)中,你可以將程序運(yùn)行起來(lái)之后,強(qiáng)制中斷測(cè)試一下,會(huì)發(fā)現(xiàn)是一個(gè)空文件。

with open('test.txt', 'w', encoding='UTF-8') as fp:
	fp.write('我和我的祖國(guó),一刻也不能分割。')
	while True:
		pass

手動(dòng)刷新

上面的例子中,文件沒(méi)有辦法關(guān)閉,程序沒(méi)有辦法執(zhí)行完成,貌似緩沖區(qū)也很難寫滿,難道我們的內(nèi)容就沒(méi)有辦法保存了嗎?

你機(jī)智的寫上了一行代碼,是close()函數(shù),這樣就關(guān)閉了文件,就可以將死循環(huán)之前的內(nèi)容保存了嘛。

with open('test.txt', 'w', encoding='UTF-8') as fp:
	fp.write('我和我的祖國(guó),一刻也不能分割。')
	fp.close()	# 關(guān)閉文件
	while True:
		pass

你經(jīng)過(guò)測(cè)試,上面的代碼的確的保存了寫入的內(nèi)容,但是我們關(guān)閉了文件,再次操作文件的時(shí)候就必須重新開(kāi)啟文件,不然沒(méi)有辦法繼續(xù)操作。

with open('test.txt', 'w', encoding='UTF-8') as fp:
	fp.write('我和我的祖國(guó),一刻也不能分割。')
	fp.close()
	fp.write('我和我的祖國(guó),就像是海和浪花一朵。')   # error,文件已經(jīng)關(guān)閉
	while True:
		pass

發(fā)現(xiàn)寫入的第二條內(nèi)容根本就沒(méi)法執(zhí)行了,怎么辦?使用fiush()函數(shù)手動(dòng)刷新緩沖區(qū)。

with open('test.txt', 'w', encoding='UTF-8') as fp:
	fp.write('我和我的祖國(guó),一刻也不能分割。')
	fp.flush()
	fp.write('我和我的祖國(guó),就像是海和浪花一朵。')
    fp.flush()
	while True:
		pass

發(fā)現(xiàn)手動(dòng)刷新將內(nèi)容保存了下來(lái),而且沒(méi)有影響程序的執(zhí)行。以后如果程序任務(wù)過(guò)大,沒(méi)有執(zhí)行完成就意外中斷,這樣就有一點(diǎn)數(shù)據(jù)保存不下來(lái)的風(fēng)險(xiǎn),我們就可以隔著一段任務(wù)手動(dòng)刷新一下,就不至于將所有的數(shù)據(jù)全部丟失。

文件的擴(kuò)展模式

我們經(jīng)過(guò)上面的學(xué)習(xí),用到了寫、讀、手動(dòng)刷新、關(guān)閉文件等幾種操作文件的函數(shù),但是除此之外,還有一些常用的相關(guān)函數(shù)。

函數(shù)作用
write寫入數(shù)據(jù)
read讀取數(shù)據(jù)
fiush手動(dòng)刷新緩沖區(qū)
close關(guān)閉文件
seek調(diào)整指針(光標(biāo))的位置
tell返回當(dāng)前指針左側(cè)所有的字節(jié)數(shù)
readable判斷文件對(duì)象是否可讀
writeable判斷文件對(duì)象是否可寫
readline讀取文件的一行內(nèi)容
readlines將文件中的內(nèi)容按照換行讀取到列表當(dāng)中
writelines將內(nèi)容是字符串的可迭代數(shù)據(jù)寫入文件當(dāng)中
truncate把要截取的字符串提取出來(lái),然后清空內(nèi)容并將截取的內(nèi)容重新寫入

read的使用

plus增強(qiáng)模式的使用

在open函數(shù)中,使用 + 號(hào),進(jìn)入增強(qiáng)模式,可讀可寫。

我們現(xiàn)在使用 r+ 模式打開(kāi)之前的文件,讀取其中的內(nèi)容。

with open('test.txt', 'r+', encoding='UTF_8') as fp:
	# 讀取內(nèi)容
	res = fp.read()
	print(res)  # 我和我的祖國(guó),一刻也不能分割。我和我的祖國(guó),就像是海和浪花一朵。
	
	# 可以指定字符的個(gè)數(shù),讀取指定個(gè)數(shù)的字符
	res = fp.read(5)
	print(res)  #

發(fā)現(xiàn)什么第二遍沒(méi)有讀取出任何的內(nèi)容,我們重新打開(kāi)一遍文件,重新讀取。

with open('test.txt', 'r+', encoding='UTF_8') as fp:
	# 讀取五個(gè)字符
	res = fp.read(5)
	print(res)  # 我和我的祖

	# 再讀取五個(gè)字符
	res = fp.read(5)
	print(res)  # 國(guó),一刻也

發(fā)現(xiàn)第二遍讀取的內(nèi)容是接著第一遍讀取的內(nèi)容之后的,我們重新打開(kāi)一遍文件,寫一些內(nèi)容。

with open('test.txt', 'r+', encoding='UTF_8') as fp:
	# 寫入內(nèi)容
	fp.write('我永遠(yuǎn)和我的祖國(guó)在一起')
	# 讀取其中的內(nèi)容
	res = fp.read()
	print(res)  # 能分割。我和我的祖國(guó),就像是海和浪花一朵。

讀取內(nèi)容的時(shí)候,發(fā)現(xiàn)沒(méi)有我們寫入的內(nèi)容,而且讀取的文件內(nèi)容怎么看起來(lái)好怪異的感覺(jué)啊,怎么少了些內(nèi)容?

我們重新打開(kāi)文件讀取一遍

with open('test.txt', 'r+', encoding='UTF_8') as fp:
	res = fp.read()
	print(res)  # 我永遠(yuǎn)和我的祖國(guó)在一起能分割。我和我的祖國(guó),就像是海和浪花一朵。

為什么我們的寫入的內(nèi)容在文件的開(kāi)頭,而且還替換掉了原有的一部分?jǐn)?shù)據(jù)?我們上面的一系列操作為什么那么的奇怪?

這都是因?yàn)楣鈽?biāo)的作用在做怪。

光標(biāo)的作用

還記得我們之前介紹四種打開(kāi)模式的時(shí)候嗎?寫入模式光標(biāo)在文檔最后,讀取模式光標(biāo)在文檔最前,追加模式光標(biāo)在文檔最前,異或模式光標(biāo)在文檔最前。

寫入的內(nèi)容和讀取的內(nèi)容都是從光標(biāo)的位置開(kāi)始的。

read()函數(shù)默認(rèn)讀取光標(biāo)一右側(cè)所有的內(nèi)容。而不是文檔中的所有內(nèi)容,之前的測(cè)試之所以可以一次性的讀取出所有的內(nèi)容是因?yàn)槲覀兇蜷_(kāi)文檔使用的是讀取模式,光標(biāo)的位置在文檔的開(kāi)頭。光標(biāo)會(huì)隨著讀取的內(nèi)容而移動(dòng),讀取到哪個(gè)字符光標(biāo)就移動(dòng)到哪個(gè)字符的后面。

write()寫入內(nèi)容的時(shí)候是覆蓋模式。我們都知道我們的計(jì)算機(jī)系統(tǒng)中的文本輸入方式是有兩種的,使用insert鍵就可以切換著兩種模式。一種是插入模式,一種是覆蓋模式。

插入模式是我們平常最經(jīng)常使用的,比如說(shuō)我們打開(kāi)一個(gè)文本編輯軟件,隨便的寫入一段內(nèi)容,然后把光標(biāo)移動(dòng)到文檔的開(kāi)頭,寫入內(nèi)容,發(fā)現(xiàn)新的內(nèi)容是插入到了舊的內(nèi)容之前的,舊的內(nèi)容不會(huì)消失,而是后移,這就是插入模式;然后重新將光標(biāo)移動(dòng)到文檔的開(kāi)頭,然后按下insert鍵,這個(gè)時(shí)候你的輸入方式就變成了覆蓋模式,現(xiàn)在的你每當(dāng)輸入一個(gè)新的字符就會(huì)覆蓋掉后面的一個(gè)舊字符,這就是覆蓋模式,python的文本編輯就是這種覆蓋模式。光標(biāo)隨著寫入的內(nèi)容向后移動(dòng)。

光標(biāo)位置的移動(dòng)

我們剛才的時(shí)候就了解到了有一個(gè)可以調(diào)整光標(biāo)位置的函數(shù),叫做seek,使用這個(gè)函數(shù)我們可以隨意的調(diào)節(jié)光標(biāo)的位置,從而編輯文件的時(shí)候可以更加的隨心所欲。

seek(offset: int, [whence: int = 0])
seek(偏移量, [基準(zhǔn)位置])

seek函數(shù)的兩個(gè)參數(shù)都是整型。

第一個(gè)參數(shù)表示的是偏移量,單獨(dú)使用時(shí)表示將光標(biāo)移動(dòng)到從文檔的開(kāi)頭算起的第N個(gè)字節(jié)的位置后;
第二個(gè)參數(shù)表示的光標(biāo)的位置,使用的時(shí)候只有0、1、2三個(gè)選型,且偏移量必須為0;
0代表的是文檔的最開(kāi)端
1代表的是光標(biāo)的當(dāng)前位置
2代表的是文檔的最后端

# 先使用 w+ 模式打開(kāi)一個(gè)文件,這個(gè)時(shí)候的文件為空,光標(biāo)在文檔的開(kāi)頭位置
with open('test.txt', 'w+', encoding='UTF-8') as fp:
	
	# 我們寫入內(nèi)容,這個(gè)時(shí)候光標(biāo)的位置隨著寫入的內(nèi)容到了文檔的最后
	fp.write('hello motherland.')
	
	# 所以現(xiàn)在的光標(biāo)的右側(cè)沒(méi)有任何一個(gè)字節(jié)符,所以讀不出任何的內(nèi)容
	res = fp.read()
	print(repr(res))    # ''
	
	# 所以光標(biāo)還是在最后的位置,使用seek切換光標(biāo)的位置為開(kāi)頭,讀取剛才寫入的內(nèi)容
	fp.seek(0)
	res = fp.read()
	print(repr(res))    # 'hello motherland.'
	
	# 讀取完內(nèi)容之后,光標(biāo)又到了文檔的最后的位置,調(diào)整到開(kāi)頭的第五個(gè)字節(jié)符的位置
	fp.seek(5)
	
	# 再次讀取文件的內(nèi)容,這一次只讀取5個(gè)字符,發(fā)現(xiàn)前五個(gè)字符沒(méi)有了
	res = fp.read(5)
	print(repr(res))    # ' moth'
	
	# 現(xiàn)在光標(biāo)在文檔的第十個(gè)字符位置,我們將光標(biāo)切換到文檔的最后,然后讀取文檔發(fā)現(xiàn)什么內(nèi)容也沒(méi)有
	fp.seek(0, 2)
	res = fp.read()
	print(repr(res))    # ''

注意到了嗎?我說(shuō)的seek移動(dòng)的是字節(jié)的數(shù)量,什么是字節(jié)的數(shù)量?

我們之前說(shuō)的不同的編碼格式對(duì)于不同的字符都是不一樣的,但是所有的編碼格式對(duì)于英文字母為主的一些的字符都是一個(gè)字節(jié)的大小,但是漢字不一樣,漢字在GB中是兩個(gè)字節(jié)、UTF中是三個(gè)字節(jié)、Unicode中是四個(gè)字節(jié)。

seek的偏移單位是字節(jié),不是字符,所以在使用seek在操作bytes字節(jié)流時(shí),要注意移動(dòng)的間隔,因?yàn)橐苿?dòng)的是字節(jié)位數(shù),而在GB編碼中一個(gè)漢字兩個(gè)字節(jié),在Unicode(UTF-8)中,一個(gè)漢字三個(gè)字節(jié),如果seek將指針移動(dòng)至漢字之間,就會(huì)導(dǎo)致讀取時(shí)漢字的編碼不完整而導(dǎo)致錯(cuò)誤。

# 重新寫入一個(gè)文件,注意我們的編碼格式
with open('test.txt', 'w+', encoding='UTF-8') as fp:

	fp.write('我和我的祖國(guó),一刻也不能分割。我和我的祖國(guó),就像是海和浪花一朵。')

	# 我們現(xiàn)在讀取除了第一句話之后的內(nèi)容,前面的內(nèi)容一共是15個(gè)字符,我們使用seek跳過(guò)去
	fp.seek(15)
	res = fp.read()
	print(repr(res))    # '國(guó),一刻也不能分割。我和我的祖國(guó),就像是海和浪花一朵。'

	# 咦?怎么只跳過(guò)了五個(gè)漢字?因?yàn)槲覀兪褂玫腢TF-8的編碼,一個(gè)漢字由3個(gè)字節(jié),真好是15個(gè)單位

	# 你是幸運(yùn)的,如果我們?cè)谟乙埔粋€(gè)字節(jié)的單位,就是一個(gè)漢字都沒(méi)有完全遷移完會(huì)怎么樣?
	fp.seek(1)
	# res = fp.read()
	# print(res)      # error, 報(bào)錯(cuò)了,因?yàn)槭O碌淖址皇峭暾?,所以沒(méi)有辦法讀出,就報(bào)錯(cuò)了
# 就像是你好的UTF-8編碼是六個(gè)字節(jié)組成的,
print('你好'.encode())    # b'\xe4\xbd\xa0\xe5\xa5\xbd'

# 如果去掉了一個(gè)字節(jié),就是不完整的了,還能解碼出來(lái)嗎?
print(b'\xbd\xa0\xe5\xa5\xbd'.decode()) # error,解碼失敗

所以在使用seek函數(shù)的時(shí)候一定要慎用。

tell的使用

# tell 當(dāng)前光標(biāo)左側(cè)所有的字節(jié)數(shù)(返回字節(jié)數(shù))

# 使用閱讀模式打開(kāi)文件
with open('test.txt', 'r+', encoding='UTF-8') as fp:

   # 使用tell函數(shù)查看貫標(biāo)左側(cè)的字節(jié)數(shù)
   res = fp.tell()
   print(res)  # 0

   # 因?yàn)殚喿x模式的光標(biāo)在文件的開(kāi)頭,所以返回0個(gè)字節(jié)數(shù)

   # 使用seek將光標(biāo)移動(dòng)到文檔的末尾
   fp.seek(0, 2)

   # 使用tell查看整個(gè)文檔的字節(jié)數(shù),這就是文檔的大小
   res = fp.tell()
   print(res)  # 96

   # 快去看看你的文件信息中的文件大小是不是96字節(jié)的?

其它的相關(guān)函數(shù)

判斷文件對(duì)象可讀可寫

# 使用 r+ 模式打開(kāi)文件
with open('test.txt', 'r+', encoding='UTF-8') as fp:
   # 使用readable 和 readable 查看這個(gè)文檔是否可讀可寫
   if fp.readable():
      print('本文檔可讀')
   if fp.writable():
      print('本文檔可寫')
'''
結(jié)果:
本文檔可讀
本文檔可寫
'''

readline

讀取一行內(nèi)容

# 打開(kāi)文件,重新寫入多行內(nèi)容
with open('test.txt', 'w+', encoding='UTF-8') as fp:
   # 可以使用多行字符串
   fp.write('''11111
22222
33333
''')

   # 也可以使用轉(zhuǎn)義字符進(jìn)行換行
   fp.write('44444\n55555\n66666')

with open('test.txt', 'r+', encoding='UTF-8') as fp:

   # 使用read讀取的整個(gè)文檔的內(nèi)容
   res = fp.read()
   print(res)
   '''
   結(jié)果:
   11111
   22222
   33333
   44444
   55555
   66666
   '''

   # 使用readline讀取一一行的內(nèi)容
   fp.seek(0)
   res = fp.readline()
   print(res)  # 11111

   # 再讀取一行
   res = fp.readline()
   print(res)  # 22222

   # 可以指定讀取的字符個(gè)數(shù)
   res = fp.readline(3)
   print(res)  # 333

   # 如果指定的個(gè)數(shù)大于本行的字符個(gè)數(shù),就讀取本行所有的內(nèi)容
   res = fp.readline(1000)
   print(res)  # 33
   
   # 為什么是33不是44444?因?yàn)閞eadline也要受到光標(biāo)的影響

readlines

將文件中的內(nèi)容按照換行讀取到列表中

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不會(huì)影響光標(biāo)的移動(dòng),但是讀取的是光標(biāo)的右側(cè)數(shù)據(jù);而且readlines的讀取將換行符也讀取上了,因?yàn)閾Q行符本身也是一行的內(nèi)容。

按行讀取內(nèi)容我一般使用到readlines函數(shù),但是也可以使用其它的方法,比如直接遍歷open實(shí)例化對(duì)象,open實(shí)例化對(duì)象本身就是一個(gè)可迭代對(duì)象,它將文件中的內(nèi)容按照換行符分開(kāi)。

with open('text.txt', 'r', encoding='UTF-8') as fp:
    for line in fp:
        print(line)

writelines

將內(nèi)容是字符串的可迭代性數(shù)據(jù)寫入文件中,writelines不會(huì)根據(jù)元素?fù)Q行。

lst = ['china', 'america', 'russia']

with open('test.txt', 'w+', encoding='UTF-8') as fp:
    # 使用writelines寫入內(nèi)容
    fp.writelines(lst)
	fp.seek(0)
    # 讀取數(shù)據(jù)
	res = fp.readlines()
	print(res)	# ['chinaamericarussia']

truncate

文件中的內(nèi)容只保留截取的內(nèi)容。

從文件開(kāi)頭開(kāi)始,截取指定字節(jié)長(zhǎng)度的內(nèi)容,然后將文件清空,然后將截取的內(nèi)容重新填入文件中。

# 打開(kāi)一個(gè)文件
with open('test.txt', 'w+', encoding='UTF-8') as fp:

	# 寫入一段內(nèi)容
	fp.write('1234567890')

	# 保留截取的內(nèi)容,只保留前5個(gè)字節(jié)的內(nèi)容
	fp.truncate(5)

	# 查看文件的內(nèi)容
	fp.seek(0)
	res = fp.read()
	print(res)  # 12345

關(guān)于生成文件MD5心得

我在工作時(shí)需要給調(diào)用翻譯狗的一個(gè)API,用于上傳文獻(xiàn)并翻譯返回,但是對(duì)方需要文件MD5進(jìn)行驗(yàn)證,我們需要在接入接口的時(shí)候,需要將文件md5傳入,這個(gè)時(shí)候就出現(xiàn)了一些問(wèn)題,我在傳入文件和文件MD5的時(shí)候,被對(duì)方回應(yīng)文件MD5不匹配,我很好奇,為什么會(huì)出現(xiàn)這樣的情況?

我在使用這個(gè)接口當(dāng)中,有好幾處地方比如token的生成和文件md5的地方都會(huì)需要md5加密,所以為此我們專門將生成md5的代碼封裝成為一個(gè)函數(shù)(將字符串輸入,返回md5,代碼如下:

import hashlib

def enMD5(target):
    """ MD5加密 """
    res = hashlib.md5(target.encode()).hexdigest()
    return res

python中生成md5需要輸入字節(jié)流格式的數(shù)據(jù),而我一開(kāi)始只有字符串的數(shù)據(jù)需要使用md5加密,所以我在函數(shù)中將字符串變成字節(jié)流。token就是傳入字符串得到的。

但是文件md5的話可以直接讀出字節(jié)流的格式,但是因?yàn)樵偈褂眠@個(gè)函數(shù)不方便,所以我使用正常讀取文檔的方式讀取文件中的內(nèi)容,然后放入函數(shù)中,結(jié)果就是上面說(shuō)的,和對(duì)方得出的文件md5并不匹配。我自認(rèn)為我的代碼是沒(méi)有問(wèn)題的,于是我們依次查找問(wèn)題的所在,后來(lái)我發(fā)現(xiàn)網(wǎng)上很多博主的方法都是直接從文件讀取二進(jìn)制字節(jié)流的方式獲取的,我實(shí)在是沒(méi)有辦法了,就想會(huì)不會(huì)就是讀取方式的問(wèn)題呢?果然,我就發(fā)現(xiàn)不同格式讀取的出來(lái)的結(jié)果是不同的,測(cè)試的案例如下:

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='')

上述的結(jié)果為:

b'msr\r\nhello\r\r\nmotherland.'
f'msr\nhello\n\nmotherland.'

沒(méi)錯(cuò),我發(fā)現(xiàn)直接使用b模式和普通模式讀取內(nèi)容然后轉(zhuǎn)化成為bytes的結(jié)果是不同的,那么也必將導(dǎo)致最后文件md5是不正確的。大家也看到了,不管是哪一種讀取的方法其實(shí)和我寫入的內(nèi)容都是不同的,在本次的測(cè)試案例當(dāng)中對(duì)于換行有著不同的認(rèn)知,讀取的原因我沒(méi)有深入了解,但是我注意到了官方文檔中說(shuō)b模式就是專門讀取文件字節(jié)流格式的,所以以后大家生成文件md5的時(shí)候,一定要直接使用b模式讀取文件內(nèi)容。

上述的測(cè)試環(huán)境是:
python: python3.6.8_win_x64(Cpython)
system: windows_10_x64

到此這篇關(guān)于Python IO文件管理的具體使用的文章就介紹到這了,更多相關(guān)Python IO文件管理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • python3+PyQt5 實(shí)現(xiàn)Rich文本的行編輯方法

    python3+PyQt5 實(shí)現(xiàn)Rich文本的行編輯方法

    今天小編就為大家分享一篇python3+PyQt5 實(shí)現(xiàn)Rich文本的行編輯方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-06-06
  • python 利用pyttsx3文字轉(zhuǎn)語(yǔ)音過(guò)程詳解

    python 利用pyttsx3文字轉(zhuǎn)語(yǔ)音過(guò)程詳解

    這篇文章主要介紹了python 利用pyttsx3文字轉(zhuǎn)語(yǔ)音過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • python類特殊方法使用示例講解

    python類特殊方法使用示例講解

    這篇文章主要為大家介紹了python類特殊方法使用示例講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • 4種方法教你利用Python發(fā)現(xiàn)數(shù)據(jù)的規(guī)律

    4種方法教你利用Python發(fā)現(xiàn)數(shù)據(jù)的規(guī)律

    發(fā)現(xiàn)數(shù)據(jù)的規(guī)律是數(shù)據(jù)分析和數(shù)據(jù)科學(xué)中非常重要的一個(gè)步驟。這篇文章主要給大家整理了4個(gè)可以發(fā)現(xiàn)數(shù)據(jù)規(guī)律的方法,希望對(duì)大家有所幫助
    2023-03-03
  • python 遍歷字符串(含漢字)實(shí)例詳解

    python 遍歷字符串(含漢字)實(shí)例詳解

    這篇文章主要介紹了python 遍歷字符串(含漢字)實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • Django之騰訊云短信的實(shí)現(xiàn)

    Django之騰訊云短信的實(shí)現(xiàn)

    這篇文章主要介紹了Django之騰訊云短信的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • Python讀取本地文件并解析網(wǎng)頁(yè)元素的方法

    Python讀取本地文件并解析網(wǎng)頁(yè)元素的方法

    今天小編就為大家分享一篇Python讀取本地文件并解析網(wǎng)頁(yè)元素的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-05-05
  • python編程的核心知識(shí)點(diǎn)總結(jié)

    python編程的核心知識(shí)點(diǎn)總結(jié)

    在本篇文章里小編給大家整理的是一篇關(guān)于python編程的核心知識(shí)點(diǎn)總結(jié)內(nèi)容,對(duì)此有興趣的朋友們可以學(xué)習(xí)參考下。
    2021-02-02
  • Python使用Flask框架實(shí)現(xiàn)文件上傳實(shí)例

    Python使用Flask框架實(shí)現(xiàn)文件上傳實(shí)例

    這篇文章主要介紹了Python使用Flask庫(kù)文件上傳實(shí)例,用?Flask?處理文件上傳很容易,只要確保HTML表單中設(shè)置enctype="multipart/form-data"屬性就可以了,需要的朋友可以參考下
    2023-08-08
  • python?HZK16字庫(kù)使用詳解

    python?HZK16字庫(kù)使用詳解

    這篇文章主要介紹了python?HZK16字庫(kù)使用,本文結(jié)合實(shí)例代碼給大家講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-02-02

最新評(píng)論