讀寫文件是最常見的 IO 操作。通常,我們使用 input 從控制臺(tái)讀取輸入,使用 print 將內(nèi)容輸出到控制臺(tái)。實(shí)際上,我們也經(jīng)常從文件讀取輸入,將內(nèi)容寫到文件。
在 Python 中,讀文件主要分為三個(gè)步驟:
一般使用形式如下:
try:
f = open('/path/to/file', 'r') # 打開文件
data = f.read() # 讀取文件內(nèi)容
finally:
if f:
f.close() # 確保文件被關(guān)閉
注意到,我們?cè)诖a中加了 try...finally,這是因?yàn)?,如果打開和讀取文件時(shí)出現(xiàn)錯(cuò)誤,文件就沒有被關(guān)閉。為了確保在任何情況下,文件都能被關(guān)閉,我們加了 try...finally。
上面的代碼中,'r' 模式表示讀模式,open 函數(shù)的常用模式主要有:
| ‘r' | 讀模式 |
|---|---|
| ‘w' | 寫模式 |
| ‘a(chǎn)' | 追加模式 |
| ‘b' | 二進(jìn)制模式(可添加到其他模式中使用) |
| ‘+' | 讀/寫模式(可添加到其他模式中使用) |
上面的讀文件做法很繁瑣,我們可以使用 Python 的 with 語(yǔ)句來(lái)幫我們自動(dòng)調(diào)用 close 方法:
with open('/path/to/file', 'r') as f:
data = f.read()
可以看到,這種方式很簡(jiǎn)潔,而且還能在出現(xiàn)異常的情況下自動(dòng)關(guān)閉文件。
通常而言,讀取文件有以下幾種方式:
read() 或 readlines();read(size);readline();讀取所有內(nèi)容可以使用 read() 或 readlines()。我們?cè)谏厦嬉呀?jīng)介紹過(guò) read() 了,現(xiàn)在,讓我們看看 readlines()。
readlines() 方法會(huì)把文件讀入一個(gè)字符串列表,在列表中每個(gè)字符串就是一行。
假設(shè)有一個(gè)文件 data.txt,它的文件內(nèi)容如下(數(shù)字之間的間隔符是'\t'):
10 1 9 9
6 3 2 8
20 10 3 23
1 4 1 10
10 8 6 3
10 2 1 6
我們使用 readlines() 將文件讀入一個(gè)字符串列表:
with open('data.txt', 'r') as f:
lines = f.readlines()
line_num = len(lines)
print lines
print line_num
執(zhí)行結(jié)果:
['10\t1\t9\t9\n', '6\t3\t2\t8\n', '20\t10\t3\t23\n', '1\t4\t1\t10\n', '10\t8\t6\t3\n', '10\t2\t1\t6']
6
可以看到,列表中的每個(gè)元素都是一個(gè)字符串,剛好對(duì)應(yīng)文件中的每一行。
如果文件較小,一次性讀取所有內(nèi)容確實(shí)比較方便。但是,如果文件很大,比如有 100G,那就不能一次性讀取所有內(nèi)容了。這時(shí),我們構(gòu)造一個(gè)固定長(zhǎng)度的緩沖區(qū),來(lái)不斷讀取文件內(nèi)容。
看看例子:
with open('path/to/file', 'r') as f:
while True:
piece = f.read(1024) # 每次讀取 1024 個(gè)字節(jié)(即 1 KB)的內(nèi)容
if not piece:
break
print piece
在上面,我們使用 f.read(1024) 來(lái)每次讀取 1024 個(gè)字節(jié)(1KB) 的文件內(nèi)容,將其存到 piece,再對(duì) piece 進(jìn)行處理。
事實(shí)上,我們還可以結(jié)合 yield 來(lái)使用:
def read_in_chunks(file_object, chunk_size=1024):
"""Lazy function (generator) to read a file piece by piece.
Default chunk size: 1k."""
while True:
data = file_object.read(chunk_size)
if not data:
break
yield data
with open('path/to/file', 'r') as f:
for piece in read_in_chunks(f):
print piece
在某些情況下,我們希望逐行讀取文件,這時(shí)可以使用 readline() 方法。
看看例子:
with open('data.txt', 'r') as f:
while True:
line = f.readline() # 逐行讀取
if not line:
break
print line, # 這里加了 ',' 是為了避免 print 自動(dòng)換行
執(zhí)行結(jié)果:
10 1 9 9
6 3 2 8
20 10 3 23
1 4 1 10
10 8 6 3
10 2 1 6
在 Python 中,文件對(duì)象是可迭代的,這意味著我們可以直接在 for 循環(huán)中使用它們,而且是逐行迭代的,也就是說(shuō),效果和 readline() 是一樣的,而且更簡(jiǎn)潔。
看看例子:
with open('data.txt', 'r') as f:
for line in f:
print line,
在上面的代碼中,f 就是一個(gè)文件迭代器,因此我們可以直接使用 for line in f,它是逐行迭代的。
看看執(zhí)行結(jié)果:
10 1 9 9
6 3 2 8
20 10 3 23
1 4 1 10
10 8 6 3
10 2 1 6
再看一個(gè)例子:
with open(file_path, 'r') as f:
lines = list(f)
print lines
執(zhí)行結(jié)果:
['10\t1\t9\t9\n', '6\t3\t2\t8\n', '20\t10\t3\t23\n', '1\t4\t1\t10\n', '10\t8\t6\t3\n', '10\t2\t1\t6']
可以看到,我們可以對(duì)文件迭代器執(zhí)行和普通迭代器相同的操作,比如上面使用 list(open(filename)) 將 f 轉(zhuǎn)為一個(gè)字符串列表,這樣所達(dá)到的效果和使用 readlines 是一樣的。
寫文件使用 write 方法,如下:
with open('/Users/ethan/data2.txt', 'w') as f:
f.write('one\n')
f.write('two')
如果我們想往已存在的文件追加內(nèi)容,可以使用 'a' 模式,如下:
with open('/Users/ethan/data2.txt', 'a') as f:
f.write('three\n')
f.write('four')