1. 程式人生 > 其它 >10.檔案和異常

10.檔案和異常

檔案和異常

從檔案中讀取資料

要使用文字檔案中的資訊,首先需要將資訊讀取到記憶體中

讀取整個檔案

pi_digits.txt

3.1415926535
   8979323846
   2643383279

file_reader.py

with open('pi_digits.txt') as file_object:
    contents = file_object.read()
    print(contents.rstrip())

函式open()返回一個表示檔案的物件

關鍵字with在不再需要訪問檔案後將其關閉

也可以呼叫open()和close()來開啟和關閉檔案,但是如果程式有Bug,導致close()語句未執行,檔案將不會關閉,可能會導致資料丟失或受損。如果過早呼叫close(),會發現需要使用檔案時它已經關閉,會導致更多錯誤。

方法read()讀取這個檔案的全部內容,並將其作為一個長長的字串儲存在變數contents中;到達檔案末尾時返回一個空字串,顯示出來為一個空行,可用restrip()方法刪除

檔案路徑

將'pi_digits.txt'傳給open()時,Python將在當前執行的檔案所在目錄中查詢檔案

使用相對檔案路徑開啟檔案:Python到相對於當前執行的程式所在目錄進行查詢

with open('text_files\filename.txt') as file_object:

使用絕對路徑:可讀取系統任何地方的檔案

file_path = 'C:\Users\19405\Desktop\filename.txt'

with open(file_path ) as file_object:

絕對路徑通常比相對路徑更長,因此將其儲存在一個變數中,再將該變數傳遞給open()會有所幫助

逐行讀取

file_path = 'pi_digits.txt'
with open(file_path) as file_object:
    for line in file_object:
        print(line)

檔案中,每一行的末尾有一個看不見的換行符,print()語句也會加一個換行符,因此輸出的每行末尾會有兩個換行符:一個來自檔案,一個來自print()

消除多餘空白行:

print(line.rstrip())

建立一個包含檔案各行內容的列表

使用關鍵字with時,open()返回的檔案物件只在with程式碼塊內可用

filename = 'pi_digits.txt'

with open(filename) as file_object:
    lines = file_object.readlines()

for line in lines:
    print(line.rstrip())

方法readlines()從檔案中讀取每一行,並將其儲存再一個列表中

使用檔案的內容

filename = 'pi_digits.txt'

with open(filename) as file_object:
    lines = file_object.readlines()

pi_string = ''
for line in lines:
    pi_string += line.strip()

print(pi_string)
print(len(pi_string))

讀取文字檔案時,Python將其中所有文字都解讀為字串;如果讀取的是數字,要將其作為數值使用,就必須使用函式int()或者float()將其轉換為整數或浮點數

包含一百萬位的大型檔案

filename = 'pi_million_digits.txt'

--snip--

print(pi_string[:52] + '...')
print(len(pi_string))

圓周率中包含你的生日嗎

birthday = input("Enter your birthday, in the form mmddyy: ")
if birthday in pi_string:
    print("Your birthday appears in the first million digits of pi")
else:
    print("No")

寫入檔案

儲存資料最簡單的方式之一

寫入空檔案

filename = 'programming.txt'

with open(filename, 'w') as file_object:
    file_object.write("I love programming.")

open()的第二個實參:

'r':讀取模式

'w':寫入模式:檔案不存在,則自動建立;若檔案已存在,則清空該檔案

'a':附加模式

'r+':讀取和寫入模式

Python只能將字串寫入文字檔案

寫入多行

函式write()不會再你寫入的文字末尾新增換行符,因此寫入多行時需要指定換行符

filename = 'programming.txt'

with open(filename, 'w') as file_object:
    file_object.write("I love programming.\n")
    file_object.write("I love creating new games.\n")

附加到檔案

給檔案新增內容,而不是覆蓋原有的內容

附加模式

filename = 'programming.txt'

with open(filename, 'a') as file_object:
    file_object.write("I also love finding meaning in large datasets.\n")
    file_object.write("I love creating new games.\n")

異常

Python使用被稱為異常的特殊物件來管理程式執行期間發生的錯誤

每當發生錯誤時,都會建立一個異常物件

異常是使用try-except程式碼塊處理的。使用了該模組,即便出現異常,程式也將繼續執行

處理ZeroDivisionError異常

print(5/0)

程式執行失敗,並返回一個Traceback,建立了一個ZeroDivisionError物件

使用try-except程式碼塊

編寫一個try-except程式碼塊來處理可能發生的異常

try:
    print(5 / 0)
except ZeroDivisionError:
    print("You can't divide by zero")

如果try程式碼塊中的程式碼執行沒有問題,將跳過except程式碼塊;

如果try程式碼塊的程式碼導致了錯誤,Python將查詢這樣的expect程式碼塊,並執行其中的程式碼,即其中指定的錯誤與引發的錯誤相同

使用異常避免崩潰

經常用於要求使用者提供輸入的程式中

如果程式能夠妥善地處理無效輸入,就能再提示使用者提供有效輸入,而不至於崩潰

division.py

print("Give me two number, and I will divide them.")
print("Enter 'q' to quit.")

while True:
    first_number = input("\nFirst number: ")
    if first_number == 'q':
        break
    second_number = input("\nSecond number: ")
    if second_number == 'q':
        break
    answer = int(first_number) / int(second_number)
    print(answer)

second_number輸入為0會導致程式崩潰

else程式碼塊

將可能引發錯誤地程式碼放在try-except程式碼塊中,可提高這個程式地低於錯誤地能力

print("Give me two number, and I will divide them.")
print("Enter 'q' to quit.")

while True:
    first_number = input("\nFirst number: ")
    if first_number == 'q':
        break
    second_number = input("\nSecond number: ")
    if second_number == 'q':
        break
    try:
        answer = int(first_number) / int(second_number)
    except ZeroDivisionError:
        print("You can't divide by 0!")
    else:
        print(answer)

依賴於try程式碼塊成功執行地程式碼都放在else程式碼塊中

處理FileNotFoundError異常

找不到檔案

alice.py

filename = 'alice.txt'

try:
    with open(filename) as f_obj:
        contents = f_obj.read()
except FileNotFoundError:
    print("Sorry, the file " + filename + " dose not exist.")

分析文字

計算一個文字中包含多少個單詞

split()方法:根據一個字串建立一個單詞列表;以空格為分隔符拆分字串

def count_words(filename):
    """計算一個檔案大致包含多少單詞"""

    try:
        with open(filename) as f_obj:
            contents = f_obj.read()
    except FileNotFoundError:
        print("Sorry, the file " + filename + " dose not exist.")
    else:
        # 計算檔案大致包含多少個單詞
        words = contents.split()
        num_words = len(words)
        print("The file " + filename + " has about " + str(num_words) + "words.")

filename = 'alice.txt'
count_words(filename)

失敗時一聲不吭

在expect程式碼塊中明確告訴Python什麼都不要做

pass語句:讓Python什麼都不做

except FileNotFoundError:
    pass

不會出現traceback,也不會有任何輸出

決定報告哪些錯誤

憑藉經驗判斷該在程式地什麼地方包含異常處理塊,以及出現錯誤時該向使用者提供多少相關資訊

儲存資料

使用模組josn來儲存資料

使用json.dump()和json.load()

json.dump()儲存資料列表

import json

numbers = [2, 3, 5, 7, 11, 13]
filename = 'numbers.json'
with open(filename, 'w') as f_obj:
    json.dump(numbers, f_obj)

json.load()將列表讀取到記憶體中

import json

filename = 'numbers.json'
with open(filename) as f_obj:
    numbers = json.load(f_obj)

print(numbers)

儲存和讀取使用者生成的資料

import json

#如果以前儲存了使用者名稱,就載入它;否則,就提示使用者輸入使用者名稱並存儲它
filename = 'name.json'
try:
    with open(filename) as f_obj:
        username = json.load(f_obj)
except FileNotFoundError:
    username = input("What's your name: ")
    with open(filename, 'w') as f_obj:
        json.dump(username, f_obj)
        print("Hello, " + username)
else:
    print("Welcome back, " + str(username) + "!")

重構

重構:將程式碼劃分為一系列完成具體工作的函式

import json

def get_stored_username():
    """如果儲存了使用者名稱,就獲取它"""
    filename = 'name.json'
    try:
        with open(filename) as f_obj:
            username = json.load(f_obj)
    except FileNotFoundError:
        return None
    else:
        return username

def get_new_username():
    """提示使用者輸入使用者名稱"""
    username = input("What's your name: ")
    filename = 'name.json'
    with open(filename, 'w') as f_obj:
        json.dump(username, f_obj)
    return username

def greet_user():
    """問候使用者,並指出其名字"""
    username = get_stored_username()
    if username:
        print("Welcome back, " + username + "!")
    else:
        username = get_new_username()
        print("We'll remeber you when you come back, " + username + "!")

greet_user()