Python 檔案和異常
Python 檔案和異常
1、從檔案中讀取資料:
1.1、讀取整個檔案:
-
每當需要分析或修改儲存在檔案中的資訊時,讀取檔案都很有用,對資料分析應用程式來說尤其如此。
-
首先再當前目錄中建立一個.txt結尾的文字檔案,內如如下:
3.1415926535 8979323846 2643383279
-
再.py檔案中輸入:
with open('./test.txt') as file_obj: # 當前目錄名字test.txt檔案 contents = file_obj.read() print(contents)
-
函式open()
,要以任何方式使用檔案——哪怕僅僅是列印其內容,都得先開啟 檔案,這樣才能訪問它函式open()接受一個引數:要開啟的檔案的名稱。
- Python在
當前執行的檔案所在的目錄中查詢指定的檔案
- 函式open()
返回一個表示檔案的物件
。在這裡,open(‘test.txt’)返回一個表示檔案test.txt 的物件
- 將這個
物件儲存在我們將在後面使用的變數中。
-
關鍵字with 在不再需要訪問檔案後將其關閉
- 到我們呼叫了
open() ,但沒有呼叫close()
;你也可以呼叫open() 和close() 來開啟和關閉檔案
,但這樣做時,如果程式存在bug,導致close() 語句未執行,檔案將不會關閉
- 到我們呼叫了
-
我們使用
方法read()讀取這個檔案的全部內容
,並將其作為一個長長的字串儲存在變數contents
中.
-
1.2、檔案路徑:
-
要讓
Python開啟不與程式檔案位於同一個目錄中的檔案,需要提供檔案路徑 ,它讓Python到系統的特定位置去查詢。
-
由於資料夾text_files位於資料夾python_work中,因此可使用
相對檔案路徑來開啟該資料夾中的檔案
-
在Linux和OSX中可以這樣編寫程式碼:
with open('text_files/filename.txt') as file_object:
-
在Windows系統中,在檔案路徑中使用
反斜槓(\ )而不是斜槓(/ )
:with open('text_files\filename.txt') as file_object:
-
-
還可以將檔案在計算機中的準確位置告訴Python,這樣就不用關心當前執行的程式儲存在什麼地方了。
這稱為絕對檔案路徑
file_path = 'C:\Users\ehmatthes\other_files\text_files\filename.txt' with open(file_path) as file_object:
-
注意 Windows系統有時能夠正確地解讀檔案路徑中的斜槓。如果你使用的是Windows系統,且結果不符合預期,請確保在檔案路徑中使用的是反斜槓。
1.3、逐行讀取:
-
讀取檔案時,常常需要檢查其中的每一行:你可能要在檔案中查詢特定的資訊,或者要以某種方式修改檔案中的文字
file_name = './test.txt' with open(file_name) as file_obj: for line in file_obj: print(line) # 輸出結果如下: 3.1415926535 8979323846 2643383279
- 我們將要讀取的檔案的名稱儲存在
變數file_name 中,這是使用檔案時一種常見的做法
- 呼叫
open() 後,將一個表示檔案及其內容的物件儲存到了變數file_object 中
- 這裡也使用了
關鍵字with
,讓Python負責妥善地開啟
和關閉檔案
- 我們將要讀取的檔案的名稱儲存在
-
發現列印結果每行多出一個空行,
因為read() 到達檔案末尾時返回一個空字串,而將這個空字串顯示出來時就是一個空行。
-
要刪除多出來的空行,可在print 語句中使用rstrip()
file_name = './test.txt' with open(file_name) as file_obj: for line in file_obj: print(line.rstrip()) # 輸出結果如下: 3.1415926535 8979323846 2643383279
1.4、建立一個包含檔案各行內容的列表:
-
使用關鍵字with 時,open() 返回的檔案物件只在with 程式碼塊內可用
-
如果要在with 程式碼塊外訪問檔案的內容,可在
with程式碼塊內將檔案的各行儲存在一個列表中
,並
在with程式碼塊外使用該列表:file_name = './test.txt' with open(file_name) as file_obj: contents = file_obj.readlines() print(contents) for item in contents: print(item.rstrip()) # 輸出內容如下: ['3.1415926535\n', ' 8979323846\n', ' 2643383279'] 3.1415926535 8979323846 2643383279
方法readlines() 從檔案中讀取每一行,並將其儲存在一個列表中
1.5、使用檔案的內容:
-
將檔案讀取到記憶體中後,就可以以任何方式使用這些資料
file_name = './test.txt' with open(file_name) as file_obj: contents = file_obj.readlines() print(contents) pi_string = '' for item in contents: pi_string += item.rstrip() print(pi_string) print(len(pi_string)) # 輸出結果如下: ['3.1415926535\n', ' 8979323846\n', ' 2643383279'] 3.1415926535 8979323846 2643383279 34
首先開啟檔案,並將其中的所有行都儲存在一個列表中
contents- 我們建立了一個變數——
pi_string
,用於儲存圓周率的值 - 一個迴圈將各行都加入pi_string ,並刪除每行末尾的換行符
-
為了刪除兩邊的空格, 可以使用strip():
file_name = './test.txt' with open(file_name) as file_obj: contents = file_obj.readlines() print(contents) pi_string = '' for item in contents: pi_string += item.strip() print(pi_string) print(len(pi_string)) # 輸出結果如下: ['3.1415926535\n', ' 8979323846\n', ' 2643383279'] 3.141592653589793238462643383279 32
-
注意:讀取文字檔案時,Python將其中的所有文字都解讀為字串。如果你讀取的是數字,並要將其作為數值使用,就必須使用函式int() 將其轉換為整數,或使用函式float() 將其轉換為浮點數。
2、寫入檔案:
儲存資料的最簡單的方式之一是將其寫入到檔案中
。通過將輸出寫入檔案,即便關閉包含程式輸出的終端視窗,這些輸出也依然存在
2.1、寫入空檔案:
-
將文字寫入檔案,你在呼叫open() 時需要提供另一個實參
file_name = './test.txt' with open(file_name, 'w') as file_obj: file_obj.write('I love Python') # 將test.txt檔案開啟會發現 I love Python # 已經寫入進去了
- 呼叫
open() 時提供了兩個實參
:第一個實參也是要開啟的檔案的名稱
第二個實參('w' )告訴Python,我們要以寫入模式 開啟這個檔案
- 開啟檔案時,可指定
讀取模式 ('r' )
、寫入模式 ('w' )
、附加模式 ('a' )
或讓你能夠讀取和寫入檔案的模式('r+' )
。- 如果你
省略了模式實參
,Python將以預設的只讀模式開啟檔案
。 - 如果你要
寫入的檔案不存在
,函式open() 將自動建立它
- 以
寫入('w' )模式開啟檔案時千萬要小心,因為如果指定的檔案已經存在,Python將在返回檔案物件前清空該檔案。
- 如果你
- 我們使用
檔案物件的方法write() 將一個字串寫入檔案
- 呼叫
-
注意:Python只能將字串寫入文字檔案。要將數值資料儲存到文字檔案中,必須先使用函式str() 將其轉換為字串格式。
2.2、寫入多行:
-
函式write() 不會在你寫入的文字末尾新增換行符,因此如果你寫入多行時沒有指定換行符
file_name = './test.txt' with open(file_name, 'a+') as file_obj: file_obj.write('I love Python') file_obj.write('I love you') # 開啟test.txt檔案會發現 I love PythonI love you # 發現兩行內容擠在一起了
-
要讓每個字串都單獨佔一行,需要在write() 語句中包含換行符:
file_name = './test.txt' with open(file_name, 'w') as file_obj: file_obj.write('I love Python\n') file_obj.write('I love you') # 開啟test.txt 檔案會發現 I love Python I love you # 跟我們預想的是一樣的結果
2.3、附加到檔案:
-
如果你要給檔案新增內容,而不是覆蓋原有的內容,可以附加模式開啟檔案。
-
附加模式開啟檔案時,Python不會在返回檔案物件前清空檔案,而你寫入到檔案的行都將新增到檔案末尾
-
如果指定的檔案不存在,Python將為你建立一個空檔案。
file_name = './test.txt' with open(file_name, 'a') as file_obj: file_obj.write('I love Python\n') file_obj.write('I love java\n') file_obj.write('I love you') # 開啟test.txt檔案的時候,裡面已經有一段內容了 裡面已經有一段內容了 I love Python I love java I love you
- 我們
開啟檔案時指定了實參'a'
,以便將內容附加到檔案末尾,而不是覆蓋檔案原來的內容
- 我們
3、異常:
Python使用被稱為異常的特殊物件來管理程式執行期間發生的錯誤
- 每當發生讓Python不知所措的錯誤時,它都會建立一個異常物件
- 如果你編寫了
處理該異常的程式碼,程式將繼續執行
;如果你未對異常進行處理,程式將停止,並顯示一個traceback,其中包含有關異常的報告
異常是使用try-except 程式碼塊處理的。
- try-except 程式碼塊讓Python執行指定的操作,同時告訴Python發生異常時怎麼辦。使用了try-except 程式碼塊時,即便出現異常,程式也繼續執行:顯示你編寫的友好的錯誤訊息,而不是令使用者迷惑的traceback。
3.1、處理ZeroDivisionError 異常:
-
下面來看一種導致Python引發異常的簡單錯誤。你可能知道不能將一個數字除以0
print(6/0) # 會報錯 Traceback (most recent call last): File "C:/Users/lh9/PycharmProjects/request/my_test01.py", line 996, in <module> print(6/0) ZeroDivisionError: integer division or modulo by zero
- 在上述traceback中,
指出錯誤ZeroDivisionError:
是一個異常物件。 - Python無法按你的要求做時,就會建立這種物件。在這種情況下,Python將停止執行程式,並指出引發了哪種異常,而我們可根據這些資訊對程式進行修改。
- 在上述traceback中,
3.2、使用try-except程式碼塊:
-
當你認為可能發生了錯誤時,可編寫一個try-except 程式碼塊來處理可能引發的異常
try: print(6/0) except ZeroDivisionError: print('0不能被用做除數') # 輸出結果就是 0不能被用做除數
如果try 程式碼塊中的程式碼執行起來沒有問題
,Python將跳過except 程式碼塊
;- 如果
try 程式碼塊中的程式碼導致了錯誤
,Python將查詢這樣的except 程式碼塊,並執行其中的程式碼,即其中指定的錯誤與引發的錯誤相同
3.3、else程式碼塊:
-
通過將可能引發錯誤的程式碼放在try-except 程式碼塊中,可提高這個程式抵禦錯誤的能力。
-
錯誤是執行除法運算的程式碼行導致的,因此我們需要將它放到try-except 程式碼塊中。
-
這個示例還包含一個
else 程式碼塊
;依賴於try 程式碼塊成功執行的程式碼都應放到else 程式碼塊中
while True: First = input('First number:') if First == 'q': break Second = input('\nSecond number:') try: answer = int(First) / int(Second) except ZeroDivisionError: print('0不能是被除數') else: print('成功輸出') print(answer)
- Python嘗試執行try 程式碼塊中的程式碼;
- 只有可能引發異常的程式碼才需要放在try 語句中。
- 有時候,有一些僅在try 程式碼塊成功執行時才需要執行的程式碼;
- 這些程式碼應放在else 程式碼塊中。
- except 程式碼塊告訴Python,如果它嘗試執行try 程式碼塊中的程式碼時引發了指定的異常,該怎麼辦。
- Python嘗試執行try 程式碼塊中的程式碼;
3.4、處理FileNotFoundError 異常:
-
使用檔案時,一種常見的問題是找不到檔案
: -
你要查詢的檔案可能在其他地方、檔名可能不正確或者這個檔案根本就不存在。
-
對於所有這些情形,都可使用try-except 程式碼塊以直觀的方式進行處理。
filename = 'alice.txt' with open(filename) as f_obj: contents = f_obj.read()
-
python 無法讀取不存在的檔案,因此它引發一個異常:
Traceback (most recent call last): File "alice.py", line 3, in <module> with open(filename) as f_obj: FileNotFoundError: [Errno 2] No such file or directory: 'alice.txt'
-
在上述traceback中,最後一行報告了FileNotFoundError 異常,這是Python找不到要開啟的檔案時建立的異常
-
這個
錯誤是函式open() 導致的
,因此要處理這個錯誤,必須將try 語句放在包含open() 的程式碼行之前:
filename = 'alice.txt' try: with open(filename) as f_obj: contents = f_obj.read() except FileNotFoundError: msg = "Sorry, the file " + filename + " does not exist." print(msg) # 最終結果輸出如下: Sorry, the file alice.txt does not exist.
-
3.5、失敗時一聲不吭:
-
但並非每次捕獲到異常時都需要告訴使用者,有時候你希望程式在發生異常時一聲不吭,就像什麼都沒有發生一樣繼續執行。
-
要讓程式在失敗時一聲不吭,可像通常那樣編寫try 程式碼塊,但在except 程式碼塊中明確地告訴Python什麼都不要做。
-
Python有一個pass 語句,可在程式碼塊中使用它來讓Python什麼都不要做
:try: print(6/0) except ZeroDivisionError: pass print('Except 丟擲的異常什麼都沒有, 使用了pass語句')
-
pass 語句還充當了佔位符,它提醒你在程式的某個地方什麼都沒有做,並且以後也許要在這裡做些什麼。
4、儲存資料:
模組json 讓你能夠將簡單的Python資料結構轉儲到檔案中,並在程式再次執行時載入該檔案中的資料
你還可以使用json 在Python程式之間分享資料。
- 更重要的是,
json資料格式並非Python專用的,這讓你能夠將以JSON格式儲存的資料與使用其他程式語言的人分享
4.1、使用json.dump()和json.load():
-
函式json.dump() 接受兩個實參:要儲存的資料以及可用於儲存資料的檔案物件。
import json numbers = [2, 3, 5, 7, 11, 13] file_name = 'numbers.json' with open(file_name, 'w') as f_obj: json.dump(numbers, f_obj) # 開啟nubers.json的檔案 內容如下: [2, 3, 5, 7, 11, 13]
- 我們先匯入模組json ,再建立一個數字列表,指定了要將該數字列表儲存到其中的檔案的名稱.
- 通常使用副檔名.json來指出檔案儲存的資料為JSON格式
- 我們使用函式json.dump() 將數字列表儲存到檔案numbers.json中。
-
使用json.load() 將這個列表讀取到記憶體中
:import json numbers = [2, 3, 5, 7, 11, 13] file_name = 'numbers.json' with open(file_name) as f_obj: numbers = json.load(f_obj) print(numbers) # 輸出結果如下: [2, 3, 5, 7, 11, 13]
- 我們使用函式json.load() 載入儲存在numbers.json中的資訊,並將其儲存到變數numbers 中。
- 最後,我們列印恢復的數字列表,看看它是否與number_writer.py中建立的數字列表相同