[Python]-10-檔案讀寫(上)

2021-05-04 12:00:16

引言

這篇文章介紹如何使用python的os與shutil模組,對檔案或資料夾進行讀寫、建立、刪除等操作。

文章目錄

0×1.檔案相關操作
a.建立檔案
b.讀取檔案內容
c.檔案內容追加
d.檔案讀寫異常
e.獲取副檔名
f.獲取檔案絕對路徑
g.獲取檔案大小
h.獲取檔案最新修改時間
i.檔案的移動複製與刪除

0×1.檔案相關操作

a.建立檔案

Python中建立檔案是通過內建的open()函數實現的,這個函數接收最基本的兩個引數,第一個為檔案路徑(相對或絕對路徑),第二個是對檔案的操作方式(讀寫),建立檔案有下面兩種語法:

語法一:file1=open("檔案路徑","w")

語法二:with open("檔案路徑","w") as file1:

其中file1是檔案物件名稱,引數"w"引數告訴python直譯器,建立一個可寫入資料的檔案,並在關閉資料流前,保持可寫入狀態,語法二是python3推薦的標準方法。

檔案路徑可以是相對路徑或絕對路徑,相對路徑是相對當前執行的指令碼目錄的,windows下檔案目錄中的反斜槓需要使用跳脫輸出,例如:"C:\windows\system32\filename.txt";或使用引數字首"r"取消字串中對反斜槓的特殊處理,例如:r"c:\windows\system32\filename.txt";本文所有的操作都使用ubuntu系統舉例:

#!/usr/bin/env python
#coding=utf-8
#使用語法一,在"/home/qing/test/"目錄中建立qingsword.txt檔案,如果檔案不存在則建立,如果檔案存在則覆蓋,file1.write()往這個檔案中寫入了一行資料;如果不新增引數"w"則檔案使用唯讀方式傳遞給file1物件,在唯讀模式下,如果檔案不存在則會觸發"FileNotFoundError"異常。
file1=open("/home/qing/test/qingsword.txt","w")
file1.write("www.qingsword.com")
file1.close()  #關閉檔案流
del file1      #刪除檔案物件釋放資源

#如果要輸入多行資料,可以使用三引號,python會根據三引號中的格式將每行資料寫入檔案中,三引號有點類似HTML語言中的pre標籤

#使用語法二,完成上面的操作(python3推薦)
#!/usr/bin/env python3
#coding=utf-8
with open("/home/qing/test/qingsword.txt","w") as file1:
    file1.write("""晴刃
qingsword
www.qingsword.com""")

注意到上面的兩種語法,語法二並沒有使用close()函數來關閉檔案流,這是因為with表示式內部包含兩個重要函數,__enter__和__exit__,__enter__函數負責將open()函數的返回值賦予as後面的物件(file1),最後不論該語句塊出現了什麼異常,都會在離開時執行__exit__函數,該函數會自動逐個關閉開啟的檔案物件;這樣設計的好處顯而易見,在語法一中,如果在close()函數執行前,程式出現異常退出了,那麼這個檔案流不會被正常關閉,將會一直佔用著系統資源,所以推薦使用with來開啟一個檔案。

本例使用語法二,像檔案中輸入了三行資料,下面來看看如何讀取這些資料內容。

b.讀取檔案內容

讀取檔案可以使用檔案物件的read()和readline()兩個方法,read()會一次性讀取所有的檔案內容,readline()一次唯讀一行,在讀取內容時,如果文字中有換行符(\n)也會被讀取到,但在輸出或寫入其他檔案時,這些換行符會被自動轉換成換行,請看下面的範例:

#!/usr/bin/env python3
#coding=utf-8
import os  #匯入os模組
#os.path.isfile()函數能夠判斷傳入的路徑是否為檔案,open函數中的引數"r"表示以唯讀方式開啟檔案
if os.path.isfile("/home/qing/test/qingsword.txt"):
    with open("/home/qing/test/qingsword.txt","r") as file1:
        line1=file1.readline() #讀取一整行(遇到回車符\n終止)
        print(line1)
        line1=file1.readline()
        print(line1)
        line1=file1.readline()
        print(line1)

#程式輸出,輸出中每行之間空了一行,這是因為"晴刃"和"qingsword"後面有都有一個換行符"\n",輸出文字資料後遊標被移動到了下一行,而print()函數預設情況下會新起一行輸出,所以又會再往下移動一行,才會得到下面這樣的結果
晴刃

qingsword

www.qingsword.com

#如果想去掉換行符,可以使用strip("\n")篩選掉每行前後的換行符,如下
#!/usr/bin/env python3
#coding=utf-8
import os
if os.path.isfile("/home/qing/test/qingsword.txt"):
    with open("/home/qing/test/qingsword.txt","r") as file1:
        line1=file1.readline().strip("\n")
        print(line1)
        line1=file1.readline().strip("\n")
        print(line1)
        line1=file1.readline().strip("\n")
        print(line1)

#輸出
晴刃
qingsword
www.qingsword.com

#如果一行的資料太長,一次性讀取可能會導致記憶體溢位,使用readline(字元數)可以讀取指定的字元數,例如
#!/usr/bin/env python3
#coding=utf-8
import os
if os.path.isfile("/home/qing/test/qingsword.txt"):
    with open("/home/qing/test/qingsword.txt","r") as file1:
        line1=file1.readline(2) #獲取"晴刃"兩個字元
        print(line1)
        line1=file1.readline() #獲取到"\n"回車符,當readline遇到回車符時,指定多少字元都沒有意義,因為readline遇到回車符後就返回,不會接著往下讀取
        print(line1)
        line1=file1.readline(4) #再獲取接下來4個字元"qing"
        print(line1)

#輸出,根據前面的解釋,很容易明白為什麼兩行資料間會空兩行了
晴刃


qing

除了使用上面的方式讀取檔案內容外,還有一種讀取方式,使用readlines()函數,它能夠讀取檔案中的每一行資料並儲存為一個列表,每行資料相當於列表的一個元素,可以遍歷列表每個元素輸出每一行資料,或列印出每一行的字元數,請看下面的範例:

#!/usr/bin/env python3
#coding=utf-8
import os
if os.path.isfile("/home/qing/test/qingsword.txt"):
    with open("/home/qing/test/qingsword.txt","r") as file1:
        lines=file1.readlines()
        print(lines)
        for line in lines:
            #輸出每一行的字元數(不包括回車符)
            print(len(line.strip("\n")))

#程式輸出
['晴刃\n', 'qingsword\n', 'www.qingsword.com']
2
9
17

with不僅僅能開啟單個檔案,還能一次性開啟多個檔案,如下:

#!/usr/bin/env python3
#coding=utf-8
import os
try: #新增錯誤處理
    if os.path.isfile("hello.py") and os.path.isfile("if.py"):
        #使用with來開啟一個或多個檔案(可以用逗號分隔任意多個檔案),使用with的好處是,不需要呼叫close()函數,with會在區塊執行結束後自動呼叫close()關閉這些檔案;read()函數能夠一次性讀取檔案流當前指標所在位置,到檔案結尾的所有內容
        with open("hello.py","r") as f1,open("if.py") as f2:
            print(f1.read())
            for line in f2.readlines():
                #不帶任何引數的strip()函數能夠去掉字串前後空格以及換行符與製表符等
                print(line.strip())
#如果os操作過程中遇到錯誤會被捕獲,本例並沒有對可能出現的os錯誤做細分處理
except Exception as erro:
    pass

如果我們讀取的不是一個文字檔案,是一個壓縮包檔案,一張圖片,或一個視訊檔,這個時候就需要使用"rb"引數來讀取二進位制資料流,例如:

#!/usr/bin/env python3
#coding=utf-8
import os
try:
    if os.path.isfile("cat.jpeg"):
        with open("cat.jpeg","rb") as img1:
            #讀取當前目錄下"cat.jpeg"圖片檔案二進位制資料流的前10個位元組
            print(img1.read(10))
except Exception as erro:
    pass

#程式輸出
b'\xff\xd8\xff\xe0\x00\x10JFIF'

使用引數r來讀取文字檔案預設是以utf-8編碼讀取的,如果需要讀取其他編碼的檔案,需要在open命令中新增字元編碼,例如:

#!/usr/bin/env python3
#coding=utf-8
import os
try:
    if os.path.isfile("testfile"):
        #假設testfile是以gbk編碼的,如果檔案讀取過程中遇到編碼錯誤,直接忽略錯誤,如果不新增errors關鍵字,遇到編碼錯誤時,會丟擲UnicodeDecodeError異常
        with open("testfile","r",encoding="GBK",errors="ignore") as f1:
            print(f1.read(1))
except Exception as erro:
    pass

c.檔案內容追加

在上面內容的基礎上,現在我們往qingsword.txt這個檔案中追加內容,請看下面的範例:

#!/usr/bin/env python3
#coding=utf-8
import os
file_path="/home/qing/test/qingsword.txt"
if os.path.isfile(file_path):
    #"a"參數列示開啟檔案並追加內容
    #如果不想追加的內容頂在上一次內容的後面,可以寫入一個回車符,或使用"三引號"換行輸入,在使用"三引號"的時候注意,文字的縮排也會被保留,所以本例的輸入都是頂格的
    with open(file_path,"a") as file1:
        file1.write("""
歡迎大家到我的部落格學習:
www.qingsword.com""")
    with open(file_path,"r") as file1:
        print(file1.read()) #讀取檔案所有內容並輸出

#程式輸出
晴刃
qingsword
www.qingsword.com
歡迎大家到我的部落格學習:
www.qingsword.com

現在,上面的內容已經可以讓我們將一個檔案的內容複製出來追加到另外一個檔案的末尾了,下面是一個簡單的實現:

#!/usr/bin/env python3
#coding=utf-8
import os
#建立兩個檔案,分別寫入資料
file_path_1="/home/qing/test/qingsword_1.txt"
file_path_2="/home/qing/test/qingsword_2.txt"
with open(file_path_1,"w") as file1,\
     open(file_path_2,"w") as file2:
    file1.write("""歡迎大家到我的部落格學習:
www.qingsword.com""")
    file2.write("晴刃")

#將file_path_2檔案中的內容追加到file_path_1檔案內容下
if os.path.isfile(file_path_1) and\
   os.path.isfile(file_path_2):
    with open(file_path_2,"r") as file1,\
         open(file_path_1,"a") as file2:
        file2.write("\n")
        file2.write(file1.read())

#列印出file_path_1檔案內容
if os.path.isfile(file_path_1):
    with open(file_path_1,"r") as file1:
        print(file1.read())

#程式輸出
歡迎大家到我的部落格學習:
www.qingsword.com
晴刃

d.檔案讀寫異常

在對檔案讀寫操作的時候,會出現下面這些常見的異常,如果希望程式更加的"友好",我們應該提前瞭解並使用try語句塊捕獲這些異常,下面列舉三個比較常見的異常,這些異常都屬於OSError異常類;

FileNotFoundError:當以唯讀方式開啟一個不存在的檔案,或路徑不存在時,或檔案操作過程中找不到某檔案時觸發;

PermissionError:試圖在一個沒有許可權的目錄中讀寫檔案時觸發;

IsADirectoryError:試圖往一個不存在的資料夾複製檔案時觸發;

e.獲取副檔名

os.path.splitext()函數可以用於獲取檔案的擴充套件名,請看下面的範例:

#!/usr/bin/env python
#coding=utf-8
import os
print(os.path.splitext("qingsword.exe.txt"))
print(os.path.splitext("qingsword.exe.txt")[1])

#程式輸出,os.path.splitext()函數可以將傳入的檔名稱的最後一個點後面的擴充套件名和前面的檔名稱分割成一個元組,通過存取這個元組索引位置為1的元素,就能得到檔案的擴充套件名
('qingsword.exe', '.txt')
.txt

f.獲取檔案絕對路徑

os.path.abspath()函數可用於獲取檔案的絕對路徑,這個函數無法判斷傳入的檔案是否存在,就算這個檔案不存在,仍然可以使用這個函數,函數會將檔名和當前指令碼執行的絕對路徑目錄拼接起來:

#!/usr/bin/env python
#coding=utf-8
import os
print(os.path.abspath("qingsword.txt"))

#程式輸出
/home/qing/python-lab/qingsword.txt

#如果是獲取當前指令碼所在目錄的絕對路徑,可以使用下面的語法
os.path.abspath(".")

g.獲取檔案大小

可以使用os.path.getsize()函數獲取檔案的大小,單位為byte:

import os
print(os.path.getsize("/home/qing/test/qingsword.txt"))

#輸出,qingsword.txt只有89位元組
89

h.獲取檔案最新修改時間

os.path.getmtime()函數能夠得到檔案從1970年起到上次修改之間經過的秒數,使用time模組的ctime()方法,能夠將這個秒數格式化為標準時間輸出:"星期 月 日 時:分:秒 年"

#!/usr/bin/env python
#coding=utf-8
import os
import time
file_path="/home/qing/test/qingsword.txt"
print(time.ctime(os.path.getmtime(file_path)))

#程式輸出
Mon Aug 29 17:01:00 2016

i.檔案的移動複製與刪除

python中可以使用shutil模組來實現檔案的移動與複製,請看下面的範例:

#!/usr/bin/env python
#coding=utf-8
import os
import shutil
if os.path.isfile("qing.txt"):
    #將當前指令碼執行目錄下的qing.txt檔案複製並重新命名為qingsword.txt
    shutil.copy("qing.txt","qingsword.txt")
    os.remove("qing.txt") #刪除檔案
#isdir()函數能夠判斷目標是否為目錄
if os.path.isfile("qingsword.txt") and os.path.isdir("pack1"):
    #將剛才複製的檔案剪下移動到pack1目錄下並重新命名為qingsword.py
    shutil.move("qingsword.txt","pack1/qingsword.py")