文件和異常
????????實際開發中常常會遇到對數據進行持久化操作的場景,而實現數據持久化最直接簡單的方式就是將數據保存到文件中。
? ? ? ? 在 Python 中實現文件的讀寫操作其實非常簡單,通過 Python 內置的 open 函數,我們可以指定文件名、操作模式、編碼信息等來獲得操作文件的對象,接下來就可以對文件進行讀寫操作了。這里所說的操作模式是指要打開什么樣的文件(字符文件還是二進制文件)以及做什么樣的操作(讀、寫還是追加)。
操作模式 | 具體含義 |
r | 讀寫 |
w | 寫入(會截斷之前的內容) |
x | 寫入,如果文件已經存在會產生異常 |
a | 追加,將內容寫入到已有文件的末尾 |
b | 二進制模式 |
t | 文本模式 |
+ | 更新(可讀又可寫) |
讀寫文本文件?
?????????讀取文本文件時,需要在使用 open 函數時指定好帶路徑的文件名(可以使用相對路徑或絕對路徑)并將文件模式設置為 r?(如果不指定,默認值也是'r'
),然后通過 encoding?參數指定編碼(如果不指定,默認值是 None,那么在讀取文件時使用的是操作系統默認的編碼),如果不能保證保存文件時使用的編碼方式與 encoding 參數指定的編碼方式是一致的,那么就可能因無法解碼字符而導致讀取失敗。
def main():file = open('test.txt', 'r', encoding='utf-8')print(file.read())file.close()if __name__ == '__main__':main()
? ? ? ? 如果 open 函數指定的文件并不存在或者無法打開,那么將引發異常狀況導致程序崩潰。為了讓代碼有一定的健壯性和容錯性,我們可以使用 Python 的異常機制對可能在運行時發生狀況的代碼進行適當的處理。
def main():file = Nonetry:file = open('test.txt', 'r', encoding='utf-8')print(file.read())except FileNotFoundError:print('無法打開指定的文件!')except LookupError:print('指定了未知的編碼!')except UnicodeDecodeError:print('讀取文件時解碼錯誤!')finally:if file:file.close()if __name__ == '__main__':main()
????????在 Python?中,我們可以將那些在運行時可能會出現狀況的代碼放在 try?代碼塊中,在 try?代碼塊的后面可以跟上一個或多個 except?來捕獲可能出現的異常狀況。例如在上面讀取文件的過程中,文件找不到會引發 FileNotFoundError?,指定了未知的編碼會引發 LookupError?,而如果讀取文件時無法按指定方式解碼會引發 UnicodeDecodeError?,我們在 try?后面跟上了三個 except?分別處理這三種不同的異常狀況。最后我們使用 finally 代碼塊來關閉打開的文件,釋放掉程序中獲取的外部資源,由于 finally 塊的代碼不論程序正常還是異常都會執行到(甚至是調用了 sys?模塊的 exit?函數退出 Python 環境, finally 塊都會被執行,因為 exit?函數實質上是引發了 SystemExit?異常),因此我們通常把 finally 塊稱為“總是執行代碼塊”,它最適合用來做釋放外部資源的操作。如果不愿意在 finally 代碼塊中關閉文件對象釋放資源,也可以使用上下文語法,通過 with?關鍵字指定文件對象的上下文環境并在離開上下文環境時自動釋放文件資源。
def main():try:with open('test.txt', 'r', encoding='utf-8') as file:print(file.read())except FileNotFoundError:print('無法打開指定的文件!')except LookupError:print('指定了未知的編碼!')except UnicodeDecodeError:print('讀取文件時解碼錯誤!')if __name__ == '__main__':main()
????????除了使用文件對象的 read?方法讀取文件之外,還可以使用 for-in?循環逐行讀取或者用 readlines 方法將文件按行讀取到一個列表容器中。
def main():# 一次性讀取整個文件內容with open('test.txt', 'r', encoding='utf-8') as file:print(file.read())# 通過for-in循環逐行讀取with open('test.txt', mode='r') as file:for line in file:print(line, end='')print()# 讀取文件按行讀取到列表中with open('test.txt') as file:lines = file.readlines()print(lines)if __name__ == '__main__':main()
????????要將文本信息寫入文件文件也非常簡單,在使用 open?函數時指定好文件名并將文件模式設置為 w 即可。注意如果需要對文件內容進行追加式寫入,應該將模式設置為 a?。如果要寫入的文件不存在會自動創建文件而不是引發異常。
? ? ? ? 將1~99分別寫入兩個文件中(1~50寫入test1.txt,51~99寫入test2.txt)。
def main():filenames = ('test1.txt', 'test2.txt')file_list = []try:for filename in filenames:file_list.append(open(filename, 'a', encoding='utf-8'))for number in range(1, 100):if number < 100:file_list[0].write(str(number) + '\n')else:file_list[1].write(str(number) + '\n')except IOError as ex:print(ex)print('寫文件時發生錯誤!')finally:for file in file_list:file.close()print('操作完成!')if __name__ == '__main__':main()
讀寫二進制文件
? ? ? ? 在了解完文本文件的讀寫后,再學習二進制文件的讀寫就很簡單,只需要在模式中加入 b 即可。
? ? ? ? 實現復制圖片的功能。
def main():try:with open('tp1.jpg', 'rb') as file1:data = file1.read()print(type(data)) # <class 'bytes'>with open('tp2.jpg', 'wb') as file2:file2.write(data)except FileNotFoundError as e:print('指定的文件無法打開.')except IOError as e:print('讀寫文件異常.')if __name__ == '__main__':main()
讀寫JSON文件
? ? ? ? ?我們已經了解如何將文本數據和二進制數據保存到文件中,那么又該如何將一個列表或者一個字典中的數據保存到文件中呢?
? ? ? ? 列表和字典中的數據可以通過 JSON 格式保存到文件中。
????????JSON 是 “JavaScript Object Notation” 的縮寫,它本來是 JavaScript 語言中創建對象的一種字面量語法,現在已經被廣泛的應用于跨平臺跨語言的數據交換,原因很簡單,因為JSON也是純文本,任何系統任何編程語言處理純文本都是沒有問題的。目前 JSON 基本上已經取代了 XML 作為異構系統間交換數據的事實標準。?
? ? ? ? 簡單的 JSON 例子。?
{"name": "小明","age": 12,"phone": 1888888,"friends": ["小紅", "小白"],"toys": [{"tname": "悠悠球", "price": 25},{"tname": "陀螺", "price": 10},{"tname": "遙控汽車", "price": 200}]
}
????????上面的 JSON 跟 Python 中的字典其實是一樣一樣的,事實上 JSON 的數據類型和 Python 的數據類型是很容易找到對應關系的。
JSON | Python |
object | dict |
array | list |
string | str |
number | int/float |
true/false | True/False |
null | None |
????????使用 Python 中的 json 模塊就可以將字典或列表以 JSON 格式保存到文件中。
import jsondef main():mydict = {"name": "小明","age": 12,"phone": 1888888,"friends": ["小紅", "小白"],"toys": [{"tname": "悠悠球", "price": 25},{"tname": "陀螺", "price": 10},{"tname": "遙控汽車", "price": 200}]}try:with open('data.json', 'w', encoding='utf-8') as file:json.dump(mydict, file)except IOError as e:print(e)print('保存數據完成!')if __name__ == '__main__':main()
????????json模塊主要有四個比較重要的函數,分別是:
dump
?- 將Python對象按照JSON格式序列化到文件中dumps
?- 將Python對象處理成JSON格式的字符串load
?- 將文件中的JSON數據反序列化成對象loads
?- 將字符串的內容反序列化成Python對象
?????????序列化(serialization)在計算機科學的數據處理中,是指將數據結構或對象狀態轉換為可以存儲或傳輸的形式,這樣在需要的時候能夠恢復到原先的狀態,而且通過序列化的數據重新獲取字節時,可以利用這些字節來產生原始對象的副本(拷貝)。與這個過程相反的動作,即從一系列字節中提取數據結構的操作,就是反序列化(deserialization)。