1. 程式人生 > 其它 >Python語言基礎的異常處理-檔案操作

Python語言基礎的異常處理-檔案操作

異常

程式在執行過程當中,不可避免的會出現一些錯誤,比如:
    使用了沒有賦值過的變數
    使用了不存在的索引
    除0
    ...
這些錯誤在程式中,我們稱其為異常。
程式執行過程中,一旦出現異常將會導致程式立即終止,異常以後的程式碼全部都不會執行!    

處理異常

程式執行時出現異常,目的並不是讓我們的程式直接終止!
Python是希望在出現異常時,我們可以編寫程式碼來對異常進行處理!    

try語句
    try:
        程式碼塊(可能出現錯誤的語句)
    except 異常型別 as 異常名:
        程式碼塊(出現錯誤以後的處理方式)
    except 異常型別 as 異常名:
        程式碼塊(出現錯誤以後的處理方式)
    except 異常型別 as 異常名:
        程式碼塊(出現錯誤以後的處理方式)
    else:
        程式碼塊(沒出錯時要執行的語句)    
    finally:
        程式碼塊(該程式碼塊總會執行)    

    try是必須的 else語句有沒有都行
    except和finally至少有一個    

可以將可能出錯的程式碼放入到try語句,這樣如果程式碼沒有錯誤,則會正常執行,
    如果出現錯誤,則會執行expect子句中的程式碼,這樣我們就可以通過程式碼來處理異常
    避免因為一個異常導致整個程式的終止            
# print('hello')
# try:
#     # try中放置的是有可能出現錯誤的程式碼
#     print(10/0)
# except:
#     # except中放置的是出錯以後的處理防暑
#     print('哈哈哈,出錯了~~~')
# else:
#     print('程式正常執行沒有錯誤')    
# print('你好')


# print(10/0)


def fn():
    print('Hello fn')
    print(a)
    print(10/0)

def fn2():
    print('Hello fn2')
    fn()

def fn3():
    print('Hello fn3')
    fn2()

fn3()    

異常物件

print('異常出現前')
l = []
try:
    # print(c)
    # l[10]
    # 1 + 'hello'
    print(10/0)
except NameError:
    # 如果except後不跟任何的內容,則此時它會捕獲到所有的異常
    # 如果在except後跟著一個異常的型別,那麼此時它只會捕獲該型別的異常
    print('出現 NameError 異常')
except ZeroDivisionError:
    print('出現 ZeroDivisionError 異常')
except IndexError:
    print('出現 IndexError 異常')
# Exception 是所有異常類的父類,所以如果except後跟的是Exception,他也會捕獲到所有的異常
# 可以在異常類後邊跟著一個 as xx 此時xx就是異常物件
except Exception as e :
    print('未知異常',e,type(e))
finally :
    print('無論是否出現異常,該子句都會執行')

print('異常出現後')

異常的傳播(丟擲異常)

當在函式中出現異常時,如果在函式中對異常進行了處理,則異常不會再繼續傳播,
    如果函式中沒有對異常進行處理,則異常會繼續向函式呼叫處傳播,
    如果函式呼叫處處理了異常,則不再傳播,如果沒有處理則繼續向呼叫處傳播
    直到傳遞到全域性作用域(主模組)如果依然沒有處理,則程式終止,並且顯示異常資訊

當程式執行過程中出現異常以後,所有的異常資訊會被儲存一個專門的異常物件中,
    而異常傳播時,實際上就是異常物件拋給了呼叫處
    比如 : ZeroDivisionError類的物件專門用來表示除0的異常
            NameError類的物件專門用來處理變數錯誤的異常
            ....

在Python為我們提供了多個異常物件            

丟擲異常

- 可以使用 raise 語句來丟擲異常,
    raise語句後需要跟一個異常類 或 異常的例項
# 也可以自定義異常類,只需要建立一個類繼承Exception即可
class MyError(Exception):
    pass

def add(a,b):
    # 如果a和b中有負數,就向呼叫處丟擲異常
    if a < 0 or b < 0:
        # raise用於向外部丟擲異常,後邊可以跟一個異常類,或異常類的例項
        # raise Exception    
        # 丟擲異常的目的,告訴呼叫者這裡呼叫時出現問題,希望你自己處理一下
        # raise Exception('兩個引數中不能有負數!')  
        raise MyError('自定義的異常')
        
        # 也可以通過if else來代替異常的處理
        # return None
    r = a + b
    return r

print(add(-123,456))    

檔案(File)

- 通過Python程式來對計算機中的各種檔案進行增刪改查的操作
- I/O(Input / Output)
- 操作檔案的步驟:
    ① 開啟檔案
    ② 對檔案進行各種操作(讀、寫),然後儲存
    ③ 關閉檔案

開啟檔案

# open(file, mode='r', buffering=-1, encoding_=None, errors=None, newline=None, closefd=True, opener=None)
# 使用open函式來開啟一個檔案
# 引數:
#   file 要開啟的檔案的名字(路徑)
# 返回值:
#   返回一個物件,這個物件就代表了當前開啟的檔案

# 建立一個變數,來儲存檔案的名字
# 如果目標檔案和當前檔案在同一級目錄下,則直接使用檔名即可
file_name = 'demo.txt'

# 在windows系統使用路徑時,可以使用/來代替 \
# 或者可以使用 \\ 來代替 \
file_name = 'hello\\demo.txt'
file_name = r'hello\demo.txt' #或者也可以使用原始字串(在前面加r)

# 表示路徑,可以使用..來返回一級目錄
file_name = '../hello/demo.txt'

# 如果目標檔案距離當前檔案比較遠,此時可以使用絕對路徑
# 絕對路徑應該從磁碟的根目錄開始書寫
file_name = r'C:\Users\lilichao\Desktop\hello.txt'

# file_obj = open(file_name) # 開啟 file_name 對應的檔案

# print(file_obj)

關閉檔案

# 開啟檔案
file_name = 'demo.txt'

# 呼叫open()來開啟檔案
# file_obj = open(file_name)

# # 當我們獲取了檔案物件以後,所有的對檔案的操作都應該通過物件來進行
# # 讀取檔案中的內容
# # read()方法,用來讀取檔案中的內容,它會將內容全部儲存為一個字串返回
# content = file_obj.read()

# print(content)

# # 關閉檔案
# # 呼叫close()方法來關閉檔案
# file_obj.close()

# with ... as 語句
# with open(file_name) as file_obj :
#     # 在with語句中可以直接使用file_obj來做檔案操作
#     # 此時這個檔案只能在with中使用,一旦with結束則檔案會自動close()
#     print(file_obj.read())


file_name = 'hello'

try:
    with open(file_name) as file_obj :
        print(file_obj.read())
except FileNotFoundError:
    print(f'{file_name} 檔案不存在~~')

檔案的讀取_1

file_name = 'demo2.txt'

try:
    # 呼叫open()來開啟一個檔案,可以將檔案分成兩種型別
    # 一種,是純文字檔案(使用utf-8等編碼編寫的文字檔案)
    # 一種,是二進位制檔案(圖片、mp3、ppt等這些檔案)
    # open()開啟檔案時,預設是以文字檔案的形式開啟的,但是open()預設的編碼為None
    #   所以處理文字檔案時,必須要指定檔案的編碼
    with open(file_name,encoding='utf-8') as file_obj:
        # 通過 read() 來讀取檔案中的內容
        # 如果直接呼叫read()它會將文字檔案的所有內容全部都讀取出來
        #   如果要讀取的檔案較大的話,會一次性將檔案的內容載入到記憶體中,容易導致記憶體洩漏
        #   所以對於較大的檔案,不要直接呼叫read()
        # help(file_obj.read)
        # read()可以接收一個size作為引數,該引數用來指定要讀取的字元的數量
        #   預設值為-1,它會讀取檔案中的所有字元
        #   可以為size指定一個值,這樣read()會讀取指定數量的字元,
        #       每一次讀取都是從上次讀取到位置開始讀取的
        #       如果字元的數量小於size,則會讀取剩餘所有的
        #       如果已經讀取到了檔案的最後了,則會返回''空串
        # content = file_obj.read(-1)
        content = file_obj.read(6)#鋤禾日當午
        content = file_obj.read(6)#汗滴禾下土
        content = file_obj.read(6)#誰知盤中餐
        content = file_obj.read(6)#粒粒皆辛苦
        # print(content)
        # print(len(content))
except FileNotFoundError :
    print(f'{file_name} 這個檔案不存在!')

# 讀取大檔案的方式
file_name = 'demo.txt'

try:
    with open(file_name,encoding='utf-8') as file_obj:
        # 定義一個變數,來儲存檔案的內容
        file_content = ''
        # 定義一個變數,來指定每次讀取的大小
        chunk = 100
        # 建立一個迴圈來讀取檔案內容
        while True:
            # 讀取chunk大小的內容
            content = file_obj.read(chunk)

            # 檢查是否讀取到了內容
            if not content:
                # 內容讀取完畢,退出迴圈
                break

            # 輸出內容
            # print(content,end='')
            file_content += content

except FileNotFoundError :
    print(f'{file_name} 這個檔案不存在!')


print(file_content)

檔案的讀取_2

import pprint
import os
file_name = 'demo.txt'

with open(file_name , encoding='utf-8') as file_obj:
    # readline()
    # 該方法可以用來讀取一行內容
    # print(file_obj.readline(),end='')
    # print(file_obj.readline(),end='')
    # print(file_obj.readline(),end='')

    # readlines()
    # 該方法用於一行一行的讀取內容,它會一次性將讀取到的內容封裝到一個列表中返回
    # r = file_obj.readlines()
    # pprint.pprint(r[0])
    # pprint.pprint(r[1])
    # pprint.pprint(r[2])

    for t in file_obj:
        print(t)

    

檔案的寫入

file_name = 'demo5.txt'

# 使用open()開啟檔案時必須要指定開啟檔案所要做的操作(讀、寫、追加)
# 如果不指定操作型別,則預設是 讀取檔案 , 而讀取檔案時是不能向檔案中寫入的
# r 表示只讀的
# w 表示是可寫的,使用w來寫入檔案時,如果檔案不存在會建立檔案,如果檔案存在則會截斷檔案
#   截斷檔案指刪除原來檔案中的所有內容
# a 表示追加內容,如果檔案不存在會建立檔案,如果檔案存在則會向檔案中追加內容
# x 用來新建檔案,如果檔案不存在則建立,存在則報錯
# + 為操作符增加功能
#   r+ 即可讀又可寫,檔案不存在會報錯
#   w+ 即可讀又可寫,檔案不存在則會建立檔案
#   a+ 同w+
# with open(file_name , 'w' , encoding='utf-8') as file_obj:
# with open(file_name , 'r+' , encoding='utf-8') as file_obj:
with open(file_name , 'x' , encoding='utf-8') as file_obj:
    # write()來向檔案中寫入內容,
    # 如果操作的是一個文字檔案的話,則write()需要傳遞一個字串作為引數
    # 該方法會可以分多次向檔案中寫入內容
    # 寫入完成以後,該方法會返回寫入的字元的個數
    file_obj.write('aaa\n')
    file_obj.write('bbb\n')
    file_obj.write('ccc\n')
    r = file_obj.write(str(123)+'123123\n')
    r = file_obj.write('今天天氣真不錯')
    print(r)

對二進位制檔案的操作

file_name = 'c:/Users/lilichao/Desktop/告白氣球.flac'

# 讀取模式
# t 讀取文字檔案(預設值)
# b 讀取二進位制檔案

with open(file_name , 'rb') as file_obj:
    # 讀取文字檔案時,size是以字元為單位的
    # 讀取二進位制檔案時,size是以位元組為單位
    # print(file_obj.read(100))

    # 將讀取到的內容寫出來
    # 定義一個新的檔案
    new_name = 'aa.flac'

    with open(new_name , 'wb') as new_obj:

        # 定義每次讀取的大小
        chunk = 1024 * 100

        while True :
            # 從已有的物件中讀取資料
            content = file_obj.read(chunk)

            # 內容讀取完畢,終止迴圈
            if not content :
                break

            # 將讀取到的資料寫入到新物件中
            new_obj.write(content)

讀取檔案時的位置

# with open('demo.txt','rb') as file_obj:
#     # print(file_obj.read(100))
#     # print(file_obj.read(30))

#     # seek() 可以修改當前讀取的位置
#     file_obj.seek(55)
#     file_obj.seek(80,0)
#     file_obj.seek(70,1)
#     file_obj.seek(-10,2)
#     # seek()需要兩個引數
#     #   第一個 是要切換到的位置
#     #   第二個 計算位置方式
#     #       可選值:
#     #           0 從頭計算,預設值
#     #           1 從當前位置計算
#     #           2 從最後位置開始計算

#     print(file_obj.read())

#     # tell() 方法用來檢視當前讀取的位置
#     print('當前讀取到了 -->',file_obj.tell())

with open('demo2.txt','rt' , encoding='utf-8') as file_obj:
    # print(file_obj.read(100))
    # print(file_obj.read(30))

    # seek() 可以修改當前讀取的位置
    file_obj.seek(9)
    # seek()需要兩個引數
    #   第一個 是要切換到的位置
    #   第二個 計算位置方式
    #       可選值:
    #           0 從頭計算,預設值
    #           1 從當前位置計算
    #           2 從最後位置開始計算

    print(file_obj.read())

    # tell() 方法用來檢視當前讀取的位置
    print('當前讀取到了 -->',file_obj.tell())

檔案的其他操作

import os
from pprint import pprint

# os.listdir() 獲取指定目錄的目錄結構
# 需要一個路徑作為引數,會獲取到該路徑下的目錄結構,預設路徑為 . 當前目錄
# 該方法會返回一個列表,目錄中的每一個檔案(夾)的名字都是列表中的一個元素
r = os.listdir()

# os.getcwd() 獲取當前所在的目錄
r = os.getcwd()

# os.chdir() 切換當前所在的目錄 作用相當於 cd
# os.chdir('c:/')

# r = os.getcwd()

# 建立目錄
# os.mkdir("aaa") # 在當前目錄下建立一個名字為 aaa 的目錄

# 刪除目錄
# os.rmdir('abc')

# open('aa.txt','w')
# 刪除檔案
# os.remove('aa.txt')

# os.rename('舊名字','新名字') 可以對一個檔案進行重新命名,也可以用來移動一個檔案
# os.rename('aa.txt','bb.txt')
os.rename('bb.txt','c:/users/lilichao/desktop/bb.txt')

pprint(r)