Input/Output(輸入/輸出)
由于程序和運行時數(shù)據(jù)是在內(nèi)存中駐留法褥,由CPU這個超快的計算核心來執(zhí)行茫叭,涉及到數(shù)據(jù)交換的地方,通常是磁盤半等、網(wǎng)絡等揍愁,就需要IO接口。
比如你打開瀏覽器杀饵,訪問新浪首頁莽囤,瀏覽器這個程序就需要通過網(wǎng)絡IO
獲取新浪的網(wǎng)頁。
- 瀏覽器首先會發(fā)送數(shù)據(jù)給新浪服務器切距,告訴它我想要首頁的HTML朽缎,這個動作是往外發(fā)數(shù)據(jù),叫Output;
- 隨后新浪服務器把網(wǎng)頁發(fā)過來谜悟,這個動作是從外面接收數(shù)據(jù)话肖,叫Input。
- 所以葡幸,通常最筒,程序完成IO操作會有Input和Output兩個數(shù)據(jù)流。
當然也有只用一個的情況:
- 從磁盤讀取文件到內(nèi)存礼患,就只有Input操作是钥,
- 把數(shù)據(jù)寫到磁盤文件里,就只是一個Output操作缅叠。
Stream
Stream(流)是一個很重要的概念悄泥,可以把流想象成一個水管,
數(shù)據(jù)就是水管里的水肤粱,但是只能單向流動弹囚。
Input Stream就是數(shù)據(jù)從外面(磁盤、網(wǎng)絡)流進內(nèi)存;
Output Stream就是數(shù)據(jù)從內(nèi)存流到外面去领曼。
對于瀏覽網(wǎng)頁來說鸥鹉,瀏覽器和新浪服務器之間至少需要建立兩根水管蛮穿,才可以既能發(fā)數(shù)據(jù),又能收數(shù)據(jù)毁渗。
同步IO和異步IO
由于CPU和內(nèi)存的速度遠遠高于外設的速度践磅,所以,在IO編程中灸异,就存在速度嚴重不匹配的問題府适。
舉個例子來說,比如要把100M的數(shù)據(jù)寫入磁盤肺樟,CPU輸出100M的數(shù)據(jù)只需要0.01秒檐春,可是磁盤要接收這100M數(shù)據(jù)可能需要10秒,怎么辦呢么伯?
同步IO:CPU等著疟暖,也就是程序暫停執(zhí)行后續(xù)代碼,等100M的數(shù)據(jù)在10秒后寫入磁盤田柔,再接著往下執(zhí)行
異步IO:CPU不等待俐巴,只是告訴磁盤,“您老慢慢寫凯楔,不著急窜骄,我接著干別的事去了”,于是摆屯,后續(xù)代碼可以立刻接著執(zhí)行
一邻遏、讀文件:open-read-close(必須):with-open-read
import logging
logging.basicConfig(level=logging.INFO)
'''1
讀文件:使用Python內(nèi)置的open()函數(shù),傳入文件名和標示符虐骑;
標示符'r'表示讀准验;
'''
f=open(r'data_center_test\share\h.txt','r')
'''2
文件打開成功,調(diào)用read()方法可以一次讀取文件的全部內(nèi)容;
Python把內(nèi)容讀到內(nèi)存廷没,用一個str對象表示;
'''
logging.info(f.read())
'''3
最后調(diào)用close()方法關(guān)閉文件糊饱。
文件使用完畢后必須關(guān)閉;
因為文件對象會占用操作系統(tǒng)的資源,并且操作系統(tǒng)同一時間能打開的文件數(shù)量也是有限的
'''
f.close()
'''4
由于文件讀寫時都有可能產(chǎn)生IOError颠黎,一旦出錯另锋,后面的f.close()就不會調(diào)用。
所以狭归,為了保證無論是否出錯都能正確地關(guān)閉文件夭坪,我們可以使用try ... finally來實現(xiàn)
'''
try:
f = open(r'data_center_test\share\h.txt', 'r')
print(f.read())
finally:
if f:
f.close()
問題:關(guān)于文件路徑中轉(zhuǎn)義字符問題
- 在路徑前面加
r
,即保持字符原始值的意思过椎。
open(r'data_center_test\share\h.txt', 'r')
- 替換為雙反斜杠
open('data_center_test\\share\\h.txt', 'r')
- 替換為正斜杠
open('data_center_test/share/h.txt', 'r')
1室梅、with
Python引入了with
語句來自動幫我們調(diào)用close()方法:
with open(r'data_center_test\share\h.txt', 'r') as f:
print(f.read())
這和前面的try ... finally
是一樣的,但是代碼更佳簡潔,并且不必調(diào)用f.close()
方法
2亡鼠、read()
-
read()
:會一次性讀取文件的全部內(nèi)容赏殃; -
read(size)
:如果文件有10G,內(nèi)存就爆了间涵,所以仁热,要保險起見,可以反復調(diào)用read(size)方法勾哩,每次最多讀取size個字節(jié)的內(nèi)容 -
readline()
:可以每次讀取一行內(nèi)容股耽; -
readlines()
:一次讀取所有內(nèi)容并按行返回list;
with open(r'data_center_test\share\h.txt', 'r') as f:
for line in f.readlines():
print(line.strip())
問題:python f.read()讀取文件為空
可能原因1:
多次調(diào)用f.read()钳幅,第一次調(diào)用f.read()可以讀取到內(nèi)容,這時游標會移動到文章末尾炎滞,再次調(diào)用f.read()是獲取不到內(nèi)容的敢艰,可以使用f.seek(0)將游標移動到文章開頭再次調(diào)用f.read()即可獲取內(nèi)容。可能原因2:
在使用f.write()向文件內(nèi)寫入內(nèi)容后立刻使用f.read()讀取文件內(nèi)容册赛,這時游標也是在文件末尾的钠导,也獲取不到文本,解決方法同上森瘪。
二牡属、二進制文件
前面講的默認都是讀取文本文件,并且是UTF-8編碼的文本文件扼睬。要讀取二進制文件逮栅,比如圖片、視頻等等窗宇,用'rb'模式
打開文件即可
with open(r'data_center_test\share\1.png', 'rb') as f:
print(f.read())
b'\xff\xd8\xff\xe0\x00\........... # 十六進制表示的字節(jié)
三措伐、字符編碼
1、encoding
參數(shù):要讀取非UTF-8編碼的文本文件军俊,需要給open()函數(shù)傳入encoding
參數(shù)
2侥加、errors
參數(shù):表示如果遇到編碼錯誤或不規(guī)范的情況后直接忽略處理
(有些會報UnicodeDecodeError錯誤,因為在文本文件中可能夾雜了一些非法編碼的字符)
f = open('/Users/michael/gbk.txt', 'r', encoding='gbk', errors='ignore')
f.read()
四粪躬、寫文件:open-write-close(必須):with-open-write
但是務必要調(diào)用f.close()來關(guān)閉文件担败。
當我們寫文件時,操作系統(tǒng)往往不會立刻把數(shù)據(jù)寫入磁盤镰官,而是放到內(nèi)存緩存起來提前,空閑的時候再慢慢寫入
只有調(diào)用close()方法時,操作系統(tǒng)才保證把沒有寫入的數(shù)據(jù)全部寫入磁盤朋魔。
忘記調(diào)用close()的后果是數(shù)據(jù)可能只寫了一部分到磁盤岖研,剩下的丟失了。
所以,還是用with語句來得保險:
with open(r"data_center_test\share\h.txt", "w") as f:
f.write("你好呀")
以'w'模式寫入文件時孙援,如果文件已存在害淤,會直接覆蓋(相當于刪掉后新寫入一個文件)。
可以傳入'a'以追加(append)模式寫入
五拓售、open模式
模式 | 描述 |
---|---|
r | 以只讀方式打開文件窥摄。文件的指針將會放在文件的開頭。這是默認模式础淤。 |
rb | 以二進制格式打開一個文件用于只讀崭放。文件指針將會放在文件的開頭。這是默認模式鸽凶。一般用于非文本文件如圖片等币砂。 |
w | 打開一個文件只用于寫入。如果該文件已存在則打開文件玻侥,并從開頭開始編輯决摧,即原有內(nèi)容會被刪除。如果該文件不存在凑兰,創(chuàng)建新文件掌桩。 |
wb | 以二進制格式打開一個文件只用于寫入。如果該文件已存在則打開文件姑食,并從開頭開始編輯波岛,即原有內(nèi)容會被刪除。如果該文件不存在音半,創(chuàng)建新文件则拷。一般用于非文本文件如圖片等。 |
a | 打開一個文件用于追加曹鸠。如果該文件已存在隔躲,文件指針將會放在文件的結(jié)尾。也就是說物延,新的內(nèi)容將會被寫入到已有內(nèi)容之后宣旱。如果該文件不存在,創(chuàng)建新文件進行寫入叛薯。 |
ab | 以二進制格式打開一個文件用于追加浑吟。如果該文件已存在,文件指針將會放在文件的結(jié)尾耗溜。也就是說组力,新的內(nèi)容將會被寫入到已有內(nèi)容之后。如果該文件不存在抖拴,創(chuàng)建新文件進行寫入燎字。 |
小結(jié):
在Python中腥椒,文件讀寫是通過open()函數(shù)打開的文件對象完成的。使用with語句操作文件IO是個好習慣