目錄| 上一節(1.5 列表) | 下一節 (1.7 函式)
1.6 檔案管理
大多數的程式需要從某處讀取輸入。本節討論檔案訪問。
檔案輸入和輸出
開啟一個檔案:
f = open('foo.txt', 'rt') # Open for reading (text)
g = open('bar.txt', 'wt') # Open for writing (text)
讀取所有的資料:
data = f.read()
# Read only up to 'maxbytes' bytes
data = f.read([maxbytes])
寫入一些文字:
g.write('some text')
當你完成操作後,關閉檔案:
f.close()
g.close()
檔案應該被正確的關閉,這是很容易忘記的一個步驟。因此,首選方法是像下面這樣使用 with
語句:
with open(filename, 'rt') as file:
# Use the file `file`
...
# No need to close explicitly
...statements
當控制流離開縮排的程式碼塊時,這將會自動關閉檔案。
讀取檔案資料的習慣用法
以字串的形式一次性讀取整個檔案:
with open('foo.txt', 'rt') as file:
data = file.read()
# `data` is a string with all the text in `foo.txt`
通過迭代逐行讀取檔案:
with open(filename, 'rt') as file:
for line in file:
# Process the line
寫入檔案的習慣用法
寫入字串資料:
with open('outfile', 'wt') as out:
out.write('Hello World\n')
...
重定向 print() 函式:
with open('outfile', 'wt') as out:
print('Hello World', file=out)
...
練習
本練習依賴於 Data/portfolio.csv
檔案。該檔案由一行一行的關於股票投資組合的資訊構成。假定你是在 practical-python/Work/
目錄下進行操作。如果你不確定自己所在的目錄,你可以通過執行以下操作找出 Python 執行的目錄:
>>> import os
>>> os.getcwd()
'/Users/beazley/Desktop/practical-python/Work' # Output vary
>>>
練習 1.26: 檔案預覽
首先,嘗試以字串的形式一次性讀取整個檔案:
>>> with open('Data/portfolio.csv', 'rt') as f:
data = f.read()
>>> data
'name,shares,price\n"AA",100,32.20\n"IBM",50,91.10\n"CAT",150,83.44\n"MSFT",200,51.23\n"GE",95,40.37\n"MSFT",50,65.10\n"IBM",100,70.44\n'
>>> print(data)
name,shares,price
"AA",100,32.20
"IBM",50,91.10
"CAT",150,83.44
"MSFT",200,51.23
"GE",95,40.37
"MSFT",50,65.10
"IBM",100,70.44
>>>
在上面的示例中,應注意 Python 有兩種輸出模式。在第一種模式下,你在提示符後輸入 data
,Python 向你展示包含引號和轉義碼的原始字串。當你輸入 print(data)
時,你獲得真正的字串的格式化輸出。
一次性讀取檔案很簡單,但這通常不是最恰當的讀取檔案方式——尤其是當檔案碰巧很大或者檔案包含要一次性處理的文字行時。
要逐行讀取檔案,可以像下面這樣使用 for 迴圈:
>>> with open('Data/portfolio.csv', 'rt') as f:
for line in f:
print(line, end='')
name,shares,price
"AA",100,32.20
"IBM",50,91.10
...
>>>
當你像上面展示的那樣使用此程式碼時,它會讀取檔案的每一行,直到到達檔案末尾。在檔案末尾,迴圈會停止。
在某些特定的情況下,你可能想要手動的讀取或者跳過某一行文字(例如,可能你想跳過列標題的第一行):
>>> f = open('Data/portfolio.csv', 'rt')
>>> headers = next(f)
>>> headers
'name,shares,price\n'
>>> for line in f:
print(line, end='')
"AA",100,32.20
"IBM",50,91.10
...
>>> f.close()
>>>
next()
函式返回檔案中的下一行文字。如果你反覆呼叫該函式,將會獲得連續的行。但是,如你所知,for
迴圈已經使用 next()
函式獲取資料了。所以,通常情況下,除非你像上面展示的那樣試圖顯式跳過或者讀取一行,否則,不要直接呼叫 next()
函式。
一旦讀取檔案的各行,你就可以開始執行更多的操作,例如拆分。
示例,嘗試以下操作:
>>> f = open('Data/portfolio.csv', 'rt')
>>> headers = next(f).split(',')
>>> headers
['name', 'shares', 'price\n']
>>> for line in f:
row = line.split(',')
print(row)
['"AA"', '100', '32.20\n']
['"IBM"', '50', '91.10\n']
...
>>> f.close()
注意:在這些示例中,因為沒有使用 with
語句,所以 f.close()
被顯式的呼叫。
練習 1.27: 讀取資料檔案
現在你已經知道如何讀取檔案,讓我們編寫一個程式來執行簡單的計算。
portfolio.csv
檔案裡面的列對應股票的名稱,股票的數量以及單支股票持有的購買價格。編寫一個名為 pcost.py
的程式來開啟這個檔案,讀取所有的行並且計算在所有的股票投資組合中花費多少錢來購買這些股份。
提示:要將字串轉為整數,使用 int()
函式。要將字串轉為浮點數,使用 float()
函式。
你的程式應該列印如下輸出:
Total cost 44671.15
練習 1.28: 其它型別的“檔案"
如果你想讀取非文字檔案(如 gzip 壓縮的資料檔案)怎麼辦?雖然內建 open()
函式在這裡幫不了你了,但是 Python 提供的 gzip
模組可以讀取 gzip 檔案。
試試看:
>>> import gzip
>>> with gzip.open('Data/portfolio.csv.gz', 'rt') as f:
for line in f:
print(line, end='')
... look at the output ...
>>>
注意:此處包含 'rt'
檔案模式至關重要。如果你忘記使用它,你將會得到位元組字串而不是通常的文字字串。
說明: 我們不應該為此使用 Pandas 嗎?
資料科學家很快指出,諸如 Pandas 這樣的庫已經具有讀取 CSV 檔案的函式,為什麼不使用 Pandas 呢?的確如此——而且效果也很好。但是,這不是一門有關學習 Pandas 的課程,讀取檔案是一個比讀取 CSV 檔案更普遍的問題。我們使用 CSV 檔案做例子的主要原因是:它是大多數編碼人員熟悉的格式,並且相對易於直接使用——在讀取 CSV 檔案的過程中,闡明瞭許多 Python 特性。所以,當你回到工作中,請務必使用 Pandas。但是,在本課程剩下部分,我們將會繼續使用標準的 Python 函式。