1. 程式人生 > >Python 檔案和異常

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)
      # 輸出結果如下: 3.1415926535 8979323846 2643383279
    • 函式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將停止執行程式,並指出引發了哪種異常,而我們可根據這些資訊對程式進行修改。

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 程式碼塊中的程式碼時引發了指定的異常,該怎麼辦。

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中建立的數字列表相同