Python基础入门6_文件和异常
Python 基礎(chǔ)入門(mén)前五篇:
- Python 基礎(chǔ)入門(mén)–簡(jiǎn)介和環(huán)境配置
- Python基礎(chǔ)入門(mén)_2基礎(chǔ)語(yǔ)法和變量類(lèi)型
- Python基礎(chǔ)入門(mén)_3條件語(yǔ)句和迭代循環(huán)
- Python基礎(chǔ)入門(mén)_4函數(shù)
- Python基礎(chǔ)入門(mén)_5面向?qū)ο蠡A(chǔ)
這次將介紹有關(guān)文件和異常的處理,包括讀寫(xiě)文本文件、二進(jìn)制文件、JSON 文件,異常處理,以及 pathlib 模塊的介紹。
本文的目錄如下:
1. 文件
簡(jiǎn)介
Python 中讀取、寫(xiě)入文件,都可以通過(guò)方法 open() 實(shí)現(xiàn),該方法用于打開(kāi)一個(gè)文件,然后返回文件對(duì)象,如果文件不存在或者無(wú)法打開(kāi),會(huì)報(bào)錯(cuò) OSError。
open 方法的語(yǔ)法如下:
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)幾個(gè)參數(shù)說(shuō)明:
- file:必需,文件路徑,相對(duì)或者絕對(duì)路徑皆可;
- mode:可選,文件打開(kāi)的模式
- buffering:設(shè)置緩沖
- encoding:一般采用 utf8
- errors:報(bào)錯(cuò)級(jí)別
- newline:區(qū)分換行符
- closefd:傳入的 file 參數(shù)類(lèi)型
常用的文件打開(kāi)模式如下:
| r | 讀取(默認(rèn)文件打開(kāi)模式) |
| w | 寫(xiě)入(會(huì)截?cái)嗲懊娴膬?nèi)容) |
| x | 寫(xiě)入,如果文件已經(jīng)存在會(huì)產(chǎn)生異常 |
| a | 追加,將內(nèi)容寫(xiě)入到已有文件末尾 |
| b | 二進(jìn)制模式 |
| t | 文本模式(默認(rèn)) |
| + | 更新(既可以讀又可以寫(xiě)) |
其中 r 、 w 、a 是三選一,表明讀取或者寫(xiě)入,然后可以添加其他幾種模型,即還存在:
- rb , r+, rb+
- wb, w+, wb+
- ab, a+, ab+
對(duì)于 open 方法返回的 file 文件對(duì)象,它常用函數(shù)有:
- close():關(guān)閉文件
- flush():將內(nèi)部緩沖區(qū)數(shù)據(jù)立刻寫(xiě)入文件
- read([size]):從文件讀取指定的字節(jié)數(shù),如果沒(méi)有或者是負(fù)數(shù)值,則讀取所有
- readline():讀取整行,包含換行符 \n 字符
- readlines([sizeint]):讀取所有行并返回列表,若給定 sizeint>0,返回總和大約為 sizeint字節(jié)的行, 實(shí)際讀取值可能比 sizeint 較大, 因?yàn)樾枰畛渚彌_區(qū)。
- write(str):將字符串寫(xiě)入文件,返回的是寫(xiě)入字符的長(zhǎng)度
- writelines(sequence):向文件寫(xiě)入一個(gè)序列字符串列表,如果需要換行,需要自己添加每行的換行符
- seek(offset[, whence]):設(shè)置文件當(dāng)前位置
- tell():返回文件當(dāng)前位置。
- truncate([size]:從文件的首行首字符開(kāi)始截?cái)?#xff0c;截?cái)辔募?size 個(gè)字符,無(wú) size 表示從當(dāng)前位置截?cái)?#xff1b;截?cái)嘀蠛竺娴乃凶址粍h除,其中 Windows 系統(tǒng)下的換行代表 2個(gè)字符大小。
讀取文本文件
讀取文本文件,必須傳入文件路徑,然后打開(kāi)模式指定為 r ,接著就就是通過(guò) encoding 參數(shù)指定編碼,當(dāng)然不設(shè)置這個(gè)編碼參數(shù),它默認(rèn)值是 None ,讀取文件將采用操作系統(tǒng)默認(rèn)的編碼,通常如果文件內(nèi)容不帶有中文,這種方法是沒(méi)問(wèn)題的,如果帶有中文內(nèi)容,則必須指定 encoding='utf8' 才能正常打開(kāi)文件。
以下是一個(gè)使用例子:
# 方法1 f = open('test.txt', 'r') print(f.read()) f.close()輸出結(jié)果:
life is short, I use Python. Machine Learning Computer Vision這是第一種使用方法,這種方法的問(wèn)題就是如果忘記調(diào)用 close 方法關(guān)閉文件,會(huì)出現(xiàn)錯(cuò)誤,因此推薦使用上下文語(yǔ)法,通過(guò) with 關(guān)鍵字指定文件對(duì)象的上下文環(huán)境并在離開(kāi)上下文環(huán)境時(shí)自動(dòng)釋放文件資源,此外,讀取文件內(nèi)容,可以直接調(diào)用 read() 方法,也可以采用 for-in 循環(huán)讀取:
# 方法2 with open('test.txt', 'r') as fr:print(fr.read()) # 方法3 讀取文件也可以采用 for-in 循環(huán)逐行讀取 with open('test.txt', 'r') as fr:for line in fr:print(line.strip())2. 異常
Python 有兩種錯(cuò)誤很容易辨認(rèn):語(yǔ)法錯(cuò)誤和異常。
語(yǔ)法錯(cuò)誤也稱為解析錯(cuò),比如下面這個(gè)例子:
while Trueprint('hello')會(huì)報(bào)錯(cuò)誤,這里指出語(yǔ)法錯(cuò)誤的地方,就是缺少非常重要的冒號(hào) :
File "<ipython-input-41-b385275d6655>", line 1while True^ SyntaxError: invalid syntax而異常,是運(yùn)行期檢測(cè)到的錯(cuò)誤,即解析成功后,開(kāi)始運(yùn)行時(shí)的錯(cuò)誤,比如執(zhí)行除法操作時(shí)候,除數(shù)是 0 的情況;讀取文件的時(shí)候,文件路徑錯(cuò)誤;變量沒(méi)有定義的情況等等。
異常處理
異常的處理,就是采用 try-exception 語(yǔ)句,例子如下:
def read_file(file_name):file_contents = Nonetry:with open(file_name, 'r', encoding='utf-8') as f:file_contents = f.read()except FileNotFoundError:print('無(wú)法打開(kāi)指定的文件!')except LookupError:print('指定了未知的編碼!')except UnicodeDecodeError:print('讀取文件時(shí)解碼錯(cuò)誤!')else:print('讀取文件成功')finally:print('程序執(zhí)行完畢')return file_contents上述代碼中,try 語(yǔ)句是這樣執(zhí)行的:
- 先執(zhí)行 try 語(yǔ)句,即 try 和 except 之間的句子
- 如果沒(méi)有異常發(fā)生,就忽略 except ,然后按順序執(zhí)行 else 語(yǔ)句,finally 語(yǔ)句
- 如果發(fā)生異常,那就忽略 try 語(yǔ)句中發(fā)生異常部分后面的代碼,然后執(zhí)行和異常類(lèi)型一樣的 except 語(yǔ)句,之后執(zhí)行 finally 語(yǔ)句
- 如果一個(gè)異常沒(méi)有與任何的 except 匹配,那么這個(gè)異常將會(huì)傳遞給上層的 try 中。
一個(gè) try 語(yǔ)句可能包含多個(gè) except 子句,分別來(lái)處理不同的特定的異常。最多只有一個(gè)分支會(huì)被執(zhí)行。
處理程序?qū)⒅会槍?duì)對(duì)應(yīng)的 try 子句中的異常進(jìn)行處理,而不是其他的 try 的處理程序中的異常。
一個(gè) except 子句可以同時(shí)處理多個(gè)異常,這些異常將被放在一個(gè)括號(hào)里成為一個(gè)元組,例如:
except (FileNotFoundError, LookupError, UnicodeDecodeError) as e:print(e)上述情況,可以添加一個(gè) except 語(yǔ)句,忽略異常的名稱,它將被當(dāng)作通配符使用。你可以使用這種方法打印一個(gè)錯(cuò)誤信息,然后再次把異常拋出,如下所示:
import sysdef read_file2(file_name):file_contents = Nonetry:with open(file_name, 'r', encoding='utf-8') as f:file_contents = f.read()except (LookupError, UnicodeDecodeError) as e:print(e)except:print('發(fā)生了未知的錯(cuò)誤', sys.exc_info()[0])else:print('讀取文件成功')finally:print('程序執(zhí)行完畢')return file_contents不過(guò),其實(shí)還有一種比較偷懶的寫(xiě)法,直接用 Exception 捕獲所有異常:
import sys def read_file3(file_name):file_contents = Nonetry:with open(file_name, 'r', encoding='utf-8') as f:file_contents = f.read()except Exception as e:print(e)else:print('讀取文件成功')finally:print('程序執(zhí)行完畢')return file_contents當(dāng)然,推薦的寫(xiě)法還是前面幾種寫(xiě)法,這樣可以針對(duì)不同異常情況有不同的做法。
另外,這里的 else 語(yǔ)句是 try 語(yǔ)句執(zhí)行成功后,繼續(xù)執(zhí)行的語(yǔ)句,而 finally 則是無(wú)論是否發(fā)生異常,都會(huì)執(zhí)行的語(yǔ)句,它是定義了無(wú)論任何情況都會(huì)執(zhí)行的清理行為。
有一些方法是有預(yù)定義的清理行為,比如說(shuō)上述說(shuō)到的關(guān)鍵詞 with 語(yǔ)句,就定義了無(wú)論文件操作如何,都會(huì)執(zhí)行關(guān)閉文件對(duì)象的行為
這兩個(gè)語(yǔ)句是可選擇的,不是使用的語(yǔ)句。
拋出異常
上述的異常處理,在出現(xiàn)異常后,是可以繼續(xù)執(zhí)行后續(xù)的代碼(try-exception 后面的語(yǔ)句),即不會(huì)終止程序的執(zhí)行,但如果希望發(fā)生異常就終止程序運(yùn)行,可以采用 raise 關(guān)鍵字,如下代碼所示:
try:with open(file_name, 'r', encoding='utf-8') as f:file_contents = f.read() except Exception as e:print(e)raise或者如下所示,raise 后面加上指定的異常名稱和參數(shù)
raise NameError('HiThere')最后,更多異常處理的例子可以查看 《總結(jié):Python中的異常處理》,文章給出了關(guān)于異常的最佳實(shí)踐:
3. 更多文件和異常的例子
介紹完文件和異常,接下來(lái)介紹更多的文件操作,搭配異常處理。
寫(xiě)入文件
寫(xiě)入文件,只需要設(shè)置文件打開(kāi)模式是寫(xiě)入模型,即 w ,代碼例子如下所示,這里實(shí)現(xiàn)讀取一個(gè)文件的內(nèi)容,然后寫(xiě)入到一個(gè)新的文件中。
def save_to_file(input_file, outputfile, write_mode='w'):file_contents = read_file(input_file)try:with open(outputfile, write_mode, encoding='utf-8') as fw:fw.write(file_contents)except IOError as ioerror:print(ioerror)print('寫(xiě)入文件出錯(cuò)') input_file = 'test.txt' output_file= 'new_test.txt' save_to_file(input_file, output_file, write_mode='w')讀取二進(jìn)制文件
讀寫(xiě)文本文件的例子都有了,接下來(lái)就是二進(jìn)制文件的讀取和寫(xiě)入,這里實(shí)現(xiàn)一個(gè)復(fù)制圖片文件的功能,如下所示,讀取和保存圖片時(shí)候,采用的文件模型分別是 rb 和 wb 。
def copy_image_file(input_image, output_image):try:with open(input_image, 'rb') as img1:data = img1.read()print(type(data))with open(output_image, 'wb') as out:out.write(data)except FileNotFoundError as e:print('指定的文件無(wú)法打開(kāi)--{}'.format(input_image))except IOError as e:print('讀寫(xiě)文件出現(xiàn)錯(cuò)誤')finally:print('程序執(zhí)行結(jié)束')使用例子:
import matplotlib.pyplot as plt from PIL import Image import numpy as np input_image = 'example.jpg' output_image = 'copyed.jpg' copy_image_file(input_image, output_image)采用的用于復(fù)制的圖片如下所示:
這里,在 jupyter notebook 中展示圖片的代碼如下:
%matplotlib inline img = Image.open(input_image) print(np.asarray(img, dtype=np.uint8).shape) plt.imshow(img);這里最好一行代碼 plt.imshow(img),如果不加分號(hào),會(huì)輸出圖片變量的信息,即 <matplotlib.image.AxesImage at 0x1d0d1161dd8>,然后再顯示圖片,而加分號(hào),則直接顯示圖片。
讀寫(xiě) JSON 文件
上述介紹了如何保存文本數(shù)據(jù)和二進(jìn)制數(shù)據(jù)到文件中,但如果我們希望保存的是列表或者字典的數(shù)據(jù),那么可以選擇采用 JSON 格式。
JSON 是 JavaScript Object Notion 的縮寫(xiě),現(xiàn)在廣泛應(yīng)用于跨平臺(tái)跨語(yǔ)言的數(shù)據(jù)交換,因?yàn)樗羌兾谋?#xff0c;任何編程語(yǔ)言都可以狐貍純文本。更多關(guān)于它的介紹,可以查看官網(wǎng)–http://json.org/
JSON 的數(shù)據(jù)類(lèi)型和 Python 數(shù)據(jù)類(lèi)型的對(duì)應(yīng)關(guān)系分別如下面兩張表所示:
JSON->Python:
| object | dict |
| array | list |
| string | str |
| number(int / real) | int / float |
| true / false | True / False |
| null | None |
Python->JSON
| dict | object |
| list, tuple | array |
| str | string |
| int, float, int- & float-derived Enums | number |
| True / False | true / false |
| None | null |
在 Python 中,使用 json 庫(kù)就可以保存或者讀取 JSON 格式的文件,代碼例子如下:
import json # 先生成一個(gè)json文件 test_dict = {'name': 'python','age': 40,'package': ['os', 'json', 'sys'],'features': {'data_analysis': ['pandas', 'matplotlib'],'deep_learning': ['scikit-learn', 'tensorflow', 'pytorch', 'keras']} } try:with open('test_data.json', 'w', encoding='utf-8') as fw:json.dump(test_dict, fw, indent=4, separators=(',', ': ')) except IOError as e:print(e) finally:print('程序執(zhí)行完畢')這是一個(gè)保存為 JSON 文件的代碼,調(diào)用 dump() 方法,然后讀取代碼如下所示:
# 讀取 json 文件 try:with open('test_data.json', 'r') as fr:contents = json.load(fr)for key, val in contents.items():print('{}: {}'.format(key, val)) except IOError as e:print(e) print('讀取完畢')這里調(diào)用方法 load() 方法。
在 json 庫(kù)中比較重要的是下面四個(gè)方法:
- dump :將 Python 對(duì)象按照 JSON 格式序列化到文件中
- dumps :將 Python 對(duì)象處理為 JSON 格式的字符串
- load:將文件中的 JSON 數(shù)據(jù)反序列化為 Python 對(duì)象
- loads:將字符串內(nèi)容反序列化為 Python 對(duì)象
這里面,只要方法以 s 結(jié)尾,那就是和字符串有關(guān)系,而如果不帶,那就是和文件有關(guān)系了。
這里的序列化和反序列化,其中序列化就是指將數(shù)據(jù)結(jié)果或者對(duì)象狀態(tài)轉(zhuǎn)換為可以存儲(chǔ)或者傳輸?shù)男问?#xff0c;也就是一系列字節(jié)的形式,而從這些字節(jié)提取數(shù)據(jù)結(jié)構(gòu)的操作,就是反序列化。
在 Python 中,序列化和反序列化還可以采用 pickle 和 shelve 兩個(gè)庫(kù),但它們僅適用于 Python,不能跨語(yǔ)言。
刪除文件或者文件夾
對(duì)于刪除文件,可以采用這兩種方法,分別用到 os 和 pathlib 兩個(gè)模塊
- os.remove()
- pathlib.Path.unlink() ,這個(gè)方法也可以刪除鏈接
刪除文件夾有三種方法,不過(guò)前兩者都只能刪除空文件夾
- os.rmdir() 只能刪除空的文件夾
- pathlib.Path.rmdir() 刪除空文件夾
- shutil.rmtree() 可以刪除非空文件夾
4. pathlib 模塊
最后介紹一個(gè)在 Python 3.4 版本加入的新模塊–pathlib ,這是一個(gè)可以很好處理文件相關(guān)操作的模塊。
首先對(duì)于文件路徑,最大的問(wèn)題可能就是 Unix 系統(tǒng)和 Windows 系統(tǒng)采用的斜杠不同,前者是 / ,而后者是 \ ,因此之前的處理文件路徑拼接的方式,可以采用 os.path.join 方法,例如:
data_folder = 'source_folder/python/' file_path = os.path.join(data_folder, 'abc.txt') print(file_path) # 輸出 source_folder/python/abc.txt但現(xiàn)在有了一個(gè)更加簡(jiǎn)潔的方法,就是采用 pathlib 模塊的 Path 方法,如下所示:
from pathlib import Path data_folder = Path('source_folder/python/') file_path = data_folder / 'abc.txt' print(file_path) # 輸出 source_folder\python\abc.txt需要注意兩件事情:
當(dāng)然,pathlib 并不只是有這個(gè)用途,它還可以完成更多事情:
讀取文件內(nèi)容不需要打開(kāi)和關(guān)閉文件,如下所示,直接調(diào)用 read_text 方法即可讀取內(nèi)容
data_folder = Path('./') file_path = data_folder / 'test.txt' print(file_path.read_text())pathlib 可以更加快速容易實(shí)現(xiàn)大部分標(biāo)準(zhǔn)的文件操作,如下所示,分別執(zhí)行打印文件路徑,文件后綴,文件名(不包含文件后綴部分)、判斷文件是否存在的四個(gè)操作。
filename = Path('./test.txt') print(filename.name) # 輸出 test.txt print(filename.suffix) # 輸出 .txt print(filename.stem) # 輸出 testif not filename.exists():print('file does not exist!') else:print('file exists')可以顯式將 Unix 路徑轉(zhuǎn)換為 Windows 形式的:
from pathlib import PureWindowsPath filename = Path('source/test.txt') path_on_windows = PureWindowsPath(filename) print(path_on_windows) # 輸出 source\test.txt當(dāng)然,對(duì)于上述代碼,如果希望安全的處理斜杠,可以顯式定義為 Windows 格式的路徑,然后 pathlib 會(huì)將其轉(zhuǎn)換為可以在當(dāng)前系統(tǒng)使用的形式:
filename = PureWindowsPath('source/test.txt') correct_path = Path(filename) print(correct_path) # 在 windows 輸出 source\test.txt # 在 Mac/Linux 輸出 source/test.txt最后,還可以利用 pathlib 將相對(duì)路徑的文件解析生成如 file:// 形式的 urls,如下所示:
import webbrowser filename = Path('./test.txt') webbrowser.open(filename.absolute().as_uri())當(dāng)然,pathlib 的用法還有不少,更多的用法可以查看官網(wǎng)的介紹:
https://docs.python.org/3/library/pathlib.html
參考
- Python3 File(文件) 方法
- Python3 錯(cuò)誤和異常
- Day11–文件和異常
- JSON 的官方網(wǎng)站
- 《總結(jié):Python中的異常處理》
- https://stackoverflow.com/questions/6996603/delete-a-file-or-folder
- https://medium.com/@ageitgey/python-3-quick-tip-the-easy-way-to-deal-with-file-paths-on-windows-mac-and-linux-11a072b58d5f
- https://docs.python.org/3/library/pathlib.html
小結(jié)
本文簡(jiǎn)單介紹 Python 文件和異常的知識(shí)點(diǎn),如何讀寫(xiě)文本文件、二進(jìn)制文件和 json 文件,然后異常處理,最后介紹一個(gè)新的處理文件相關(guān)操作的模塊 pathlib .
此外,本文的代碼都上傳到我的 github 上了:
https://github.com/ccc013/Python_Notes/blob/master/Practise/file_and_exception_example.ipynb
歡迎關(guān)注我的微信公眾號(hào)–算法猿的成長(zhǎng),或者掃描下方的二維碼,大家一起交流,學(xué)習(xí)和進(jìn)步!
總結(jié)
以上是生活随笔為你收集整理的Python基础入门6_文件和异常的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 简述软件工程研究的主要内容
- 下一篇: 程序员如何与人打交道