因爲文件讀寫時都有可能產生IOError
,一旦出錯,後面的f.close()
就不會調用。因此,爲了保證不管是否出錯都能正確地關閉文件,咱們可使用try ... finally
來實現:python
try: f = open('/path/to/file', 'r') print(f.read()) finally: if f: f.close()
可是每次都這麼寫實在太繁瑣,因此,Python引入了with
語句來自動幫咱們調用close()
方法:npm
with open('/path/to/file', 'r') as f: print(f.read())
這和前面的try ... finally
是同樣的,可是代碼更佳簡潔,而且沒必要調用f.close()
方法。vim
調用read()
會一次性讀取文件的所有內容,若是文件有10G,內存就爆了,因此,要保險起見,能夠反覆調用read(size)
方法,每次最多讀取size個字節的內容。另外,調用readline()
能夠每次讀取一行內容,調用readlines()
一次讀取全部內容並按行返回list
。所以,要根據須要決定怎麼調用。api
若是文件很小,read()
一次性讀取最方便;若是不能肯定文件大小,反覆調用read(size)
比較保險;若是是配置文件,調用readlines()
最方便:app
前面講的默認都是讀取文本文件,而且是UTF-8編碼的文本文件。要讀取二進制文件,好比圖片、視頻等等,用'rb'
模式打開文件便可:ssh
>>> f = open('/Users/michael/test.jpg', 'rb') >>> f.read() b'\xff\xd8\xff\xe1\x00\x18Exif\x00\x00...' # 十六進制表示的字節
要讀取非UTF-8編碼的文本文件,須要給open()
函數傳入encoding
參數,例如,讀取GBK編碼的文件:函數
>>> f = open('/Users/michael/gbk.txt', 'r', encoding='gbk') >>> f.read() '測試'
遇到有些編碼不規範的文件,你可能會遇到UnicodeDecodeError
,由於在文本文件中可能夾雜了一些非法編碼的字符。遇到這種狀況,open()
函數還接收一個errors
參數,表示若是遇到編碼錯誤後如何處理。最簡單的方式是直接忽略:測試
>>> f = open('/Users/michael/gbk.txt', 'r', encoding='gbk', errors='ignore')
操做文件和目錄的函數一部分放在os
模塊中,一部分放在os.path
模塊中,這一點要注意一下。查看、建立和刪除目錄能夠這麼調用:編碼
# 查看當前目錄的絕對路徑: >>> os.path.abspath('.') '/Users/michael' # 在某個目錄下建立一個新目錄,首先把新目錄的完整路徑表示出來: >>> os.path.join('/Users/michael', 'testdir') '/Users/michael/testdir' # 而後建立一個目錄: >>> os.mkdir('/Users/michael/testdir') # 刪掉一個目錄: >>> os.rmdir('/Users/michael/testdir')
把兩個路徑合成一個時,不要直接拼字符串,而要經過os.path.join()
函數,這樣能夠正確處理不一樣操做系統的路徑分隔符。在Linux/Unix/Mac下,os.path.join()
返回這樣的字符串:url
part-1/part-2
而Windows下會返回這樣的字符串:
part-1\part-2
一樣的道理,要拆分路徑時,也不要直接去拆字符串,而要經過os.path.split()
函數,這樣能夠把一個路徑拆分爲兩部分,後一部分老是最後級別的目錄或文件名:
>>> os.path.split('/Users/michael/testdir/file.txt') ('/Users/michael/testdir', 'file.txt')
os.path.splitext()
能夠直接讓你獲得文件擴展名,不少時候很是方便:
>>> os.path.splitext('/path/to/file.txt') ('/path/to/file', '.txt')
這些合併、拆分路徑的函數並不要求目錄和文件要真實存在,它們只對字符串進行操做。
文件操做使用下面的函數。假定當前目錄下有一個test.txt
文件:
# 對文件重命名: >>> os.rename('test.txt', 'test.py') # 刪掉文件: >>> os.remove('test.py')
可是複製文件的函數竟然在os
模塊中不存在!緣由是複製文件並不是由操做系統提供的系統調用。理論上講,咱們經過上一節的讀寫文件能夠完成文件複製,只不過要多寫不少代碼。
幸運的是shutil
模塊提供了copyfile()
的函數,你還能夠在shutil
模塊中找到不少實用函數,它們能夠看作是os
模塊的補充。
最後看看如何利用Python的特性來過濾文件。好比咱們要列出當前目錄下的全部目錄,只須要一行代碼:
>>> [x for x in os.listdir('.') if os.path.isdir(x)] ['.lein', '.local', '.m2', '.npm', '.ssh', '.Trash', '.vim', 'Applications', 'Desktop', ...]
要列出全部的.py
文件,也只需一行代碼:
>>> [x for x in os.listdir('.') if os.path.isfile(x) and os.path.splitext(x)[1]=='.py'] ['apis.py', 'config.py', 'models.py', 'pymonitor.py', 'test_db.py', 'urls.py', 'wsgiapp.py']