給Python新手的一道面試題:如何正確讀寫文件
這是我司前段時間招人筆試中一道比較簡單題,面向初中級程序員,不過很少有人能回答完整的,問題本身不難,主要還是考察動手能力和基本代碼功,準備找工作的先收藏留著以后用得著。
看題:請指出下面代碼段中的錯誤
- >>> f = open("test.txt", mode="w")
- >>> f.write(u"python之禪")
分析:Python 提供了內建函數 open 用于讀寫文件,函數返回一個文件對象,可對文件進行讀、寫操作,用參數 mode 來控制。
默認是讀文件
- >>> f = open("test.txt")
- >>> f.read()
- python之禪
上面這段代碼如果在python2中運行,會報錯:
- Traceback (most recent call last):
- File ““, line 1, in
- UnicodeEncodeError: ‘ascii’ codec can’t encode characters in position 6-7: ordinal not in range(128)
這是一個字符編碼的問題,編碼錯誤是Python程序員最經常遇到的錯誤,之前在公眾號中寫過關于編碼錯誤的原因。
之所以報錯是程序沒法直接保存 unicode 字符串,要經過編碼轉換成而 str 類型的二進制字節序列才能夠保存。
write 方法會自動幫你做編碼轉換,默認使用 ascii 編碼格式,因為 ascii 字符集不能處理中文,所以出現了 UnicodeEncodeError 錯誤。
正確的方式是在調用 write 之前手動用 utf-8 或者 gbk 編碼轉換成 str 類型。
- >>> f = open("test.txt", mode="w")
- >>> content = u"Python之禪"
- >>> contentcontent = content.encode(encoding='utf-8')
- >>> f.write(content)
第二個問題是文件對象沒有正常關閉,有人可能要問了,不關閉會有什么影響,操作完文件時,如果不關閉文件,那么將對系統造成資源浪費,因為系統可打開的文件描述符數量是有限制,比如 Linux 是 65536,所以必須要關閉文件。
- >>> f = open("test.txt", mode="w")
- >>> content = u"Python之禪"
- >>> contentcontent = content.encode(encoding='utf-8')
- >>> f.write(content)
- >>> f.close()
close 就萬事大吉了嗎?未必。
因為有可能在調用 open 函數的時候就報錯了,比如因為權限問題沒法在該目錄讀寫文件,此時,文件對象都沒創建成功,調用close肯定會報錯。
再比如在第4行 write 的時候有可能報錯,因為磁盤空間不足,這個時候報錯了, close 方法就沒有機會執行了。
正確地做法是用 try except 對異常進行捕獲。注意,open 函數要在 try 代碼塊外面
- f = open("output.txt", "w")
- try:
- content = u"Python之禪"
- f.write(content.encode(encoding='utf-8'))
- except IOError as e:
- print("oops, %s" % e.args[0])
- finally:
- f.close()
不過,更優雅的寫法是用 with ... as 寫法,因為 文件對象實現了上下文管理器協議,程序進入 with 語句塊時,會把文件對象賦值給變量 f,在程序退出 with 語句塊的時候會地自動調用 close 方法。
- with open("output.txt", "w") as f:
- content = u"Python之禪"
- f.write(content.encode(encoding='utf-8'))
***還有一個問題是兼容性,python2 與python3 的 open 函數不一樣,后者可以在函數中指定字符編碼格式,而 python2 則沒有。
- # python3
- with open("output.txt", "w", encoding="utf-8") as f:
- content = u"Python之禪"
- f.write(content)
那么如何寫出同時兼容2和3的open函數呢?
沒錯,使用 io 模塊下的 open 函數,python2 中的 io.open 等價于 python3 中的 open 函數,可以指定 encoding 參數,同時 python3 也保留有 io.open 函數
- from io import open
- with open("output.txt", "w", encoding='utf-8') as f:
- f.write(u"python之禪")
【本文是51CTO專欄作者“劉志軍”的原創文章,作者微信公眾號:Python之禪(VTtalk)】