Python基础(十)--文件相关
目錄
?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Python基礎(十)--文件相關
1 讀寫文件
1.1 獲取文件對象
1.2 文件讀取
1.3 文件寫入
1.4 文件定位
2 文件與路徑的操作
2.1 os模塊
2.2 os.path模塊
2.3 shutil模塊
2.4 glob模塊
3 序列化
3.1 csv
3.2 json
3.3 pickle
4 上下文管理器
4.1 自定義上下文管理器
4.2?@contextmanager裝飾器
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Python基礎(十)--文件相關
1 讀寫文件
1.1 獲取文件對象
在操作系統中,一個text文檔,一張圖片,一首音樂,這些都是文件。文件會以其固有的格式保存在硬盤中。文件可以分為兩種類型:①文本文件:文本文件由若干可識別的字符組成,并且不能包含非文本字符之外的內容(圖片等),如,.txt,.bat都是文本文件,而.doc,.pdf則不是文本文件②二進制文件:由可識別的字符組成,如果我們用文本編輯器打開二進制文件,往往看到的都是一堆亂碼。
底層的角度來說,一切都是二進制格式的,文本文件,也是二進制文件的一種,只是其內容,是我們能夠識別的字符而已。
在Python中,可以通過open函數返回文件對象。文件對象是一個泛指,可以表示文件,也可以表示文件夾(路徑)。格式為:open(file, mode='r') file指定文件的路徑(相對路徑或絕對路徑),mode指定打開文件的模式,如下表。當讀入文件或者寫入文件時,會涉及到文件指針。文件指針指向的就是下一次要讀取或寫入的字符(或字節)位置,隨著讀取或寫入的進行,文件指針也會隨之而移動。
| 模式 | 說明 |
| r(1) | 讀模式(默認模式),用來讀取文件內容。文件指針在文件的開頭。文件需要事先存在,否則會產生異常。 |
| w(1) | 寫模式,用來向文件寫入數據。文件指針在文件的開頭。如果文件存在,則覆蓋文件,否則會創建文件。 |
| a(1) | 追加模式,用來向文件追加數據。文件指針在文件的末尾。如果文件存在,不會覆蓋文件(追加寫入),否則會創建文件。 |
| x(1) | 寫模式,用來向文件寫入數據。文件指針在文件的開頭。如果文件不存在,創建文件,否則產生錯誤。 |
| t(2) | 文本(字符串)模式(默認模式),以文本形式操作文件。 |
| b(2) | 二進制(字節)模式,以二進制形式操作文件。 |
| U(3) | 通用換行符模式(已不建議使用)。在該模式下,\n,\r\n或\r都會解析為換行符。不能與w、a、x或+模式同時使用(僅限于讀取文件時使用)。 |
| +(3) | 讀取或寫入。 |
上表的(1)(2)(3)模式中,不同組的模式可同時使用(除了與U不兼容的模式),例如rt,wb+等。同一組的模式同時使用,如rw,tb等。
當文件不再使用時,我們需要對文件進行關閉,從而斷開與外部文件的連接。斷開連接可以調用文件對象的close方法。
# open函數,參數1:文件路徑,參數2:操作文件的模式,返回文件對象 # 以r(讀取)模式操作文件時,文件必須存在,否則會產生FileNotFoundError fr = open("E:/test/test.txt","r") # 以w(寫入)或a(追加)模式操作文件時,文件不存在,不報錯而是創建文件 fw = open("E:/test/test1.txt","w") fa = open("E:/test/test2.txt","a") # 以x(寫入)模式操作文件時,文件必須存在,否則會產生FileNotFoundError fx = open("E:/test/test3.txt","w") # 訪問文件結束后,需要斷開與文件的連接,直接調用close并不好,可能在close方法前產生異常 # finally方式關閉文件 try:f = open("E:/test/test.txt", "r") finally:f.close() # with處打開文件,可以保證在with結束后一定能夠有效的關閉,無序顯示調用close方法 # with中可以使用as來保存文件對象(獲得文件兌現高的引用) with open("E:/test/test.txt") as f:pass1.2 文件讀取
讀取文件的幾種方式如下:
| 方法 | 描述 |
| read(size=-1) | 讀取并返回文件內容。size指定讀取的大小。如果是文本模式,以字符為單位,如果是二進制模式,以字節為單位。如果size省略,或者為負數,則返回文件的全部內容。如果文件已經沒有內容可讀取,返回空串(""或b"") |
| readlline() | 返回文件的一行,保留末尾的換行符。如果沒有內容可以讀取,返回空串(""或b"")。 |
| readllines() | 返回一個列表,列表中的每個元素為文件的一行內容,每行保留末尾的換行符。 |
文件對象也是迭代器:如果文件過大,這會占據大量的內容空間。此時readlines不是一個好的選擇。對于文件對象,其本身也是一個迭代器類型,我們可以使用for循環的方式對文件對象進行迭代,從而節省內存。
# 文件讀寫操作 with open("E:/test/test.txt","rt") as f:# t模式以字符(文本)形式操作文件,b模式以字節(二進制)形式操作文件# read讀取文件的數據,參數指定讀取的單位,如果參數缺失,或者為負值表示讀取所有# print(f.read(1))# print(f.read())pass # 如果使用了t模式,要求操作文件的編碼方式與目標文件的編碼方式一致 # 如果沒有顯示指定編碼方式,則使用平臺的編碼方式,可以使用encoding指定操作文件的編碼方式 with open("E:/test/test.txt","rt",encoding="UTF-8") as f:print(f.read())# 讀取文件的一行while True:line = f.readline()if line:print(line,end=" ")else:break# 返回一個列表,列表中的元素為每一行的內容,保留換行符# lines = f.readlines()# for line in lines:# print(line,end=" ") # 文件是迭代器類類型,每個元素就是文件的一行 from collections.abc import Iterator with open("E:/test/test.txt","rt",encoding="UTF-8") as f:print(isinstance(f,Iterator))for line in f:print(line,end="")1.3 文件寫入
向文件寫入的幾種方式如下:
| 方法 | 描述 |
| write(content) | 將參數寫入到文件中,返回寫入的長度。如果是文本模式,以字符為單位,如果是二進制模式,以字節為單位 |
| writelines(lines) | 參數lines為列表類型,將列表中所有元素寫入文件中 |
1.4 文件定位
通過文件對象的tell()和seek()方法可以獲取或設置文件指針的位置
tell():返回文件指針的位置,即下一個要讀取或寫入的字符(字節)位置。以字節為單位。
seek(offset, whence):?改變文件的指針。offset指定新的索引位置偏移量。whence指定偏移量的參照位置:0:從文件頭計算;1:從當前位置計算;2:從文件末尾計算
在文本模式下,如果whence的值不為0,則僅當offset的值為0時才是有效的。
# 文件定位 with open("E:/test/a.txt","rt",encoding="UTF-8") as f:# 返回當前文件指針的位置,以字節為單位print(f.tell())f.read(2)print(f.tell())# 改變文件指針的位置,參數1:偏移量,參數2:參照物# 在t模式下,如果第二個參數不為0,則只有第一個參數為0才支持,b模式無此限制f.seek(3,0)print(f.tell())2 文件與路徑的操作
2.1 os模塊
os模塊提供了很多操作目錄與文件的功能,常用方法如下:
| 方法名 | 描述 |
| mkdir(path) | 創建path指定的目錄。如果path所在的父目錄不存在,或者path目錄已經存在,都會產生異常 |
| makedirs(path,exist_ok=False) | 創建path指定的目錄。如果path所在的父目錄不存在,則會連同父目錄一同創建。如果path目錄已經存在,當exist_ok值為False,會產生異常,如果exist_ok值為True,則不會產生異常(默認值為False) |
| rmdir(path) | 刪除path指定的空目錄,但不會刪除父目錄。如果path目錄不存在,或者該目錄不為空,將會產生異常 |
| removedirs(path) | 刪除path指定的空目錄。如果父目錄也為空,則會連同父目錄一同刪除(一直到根目錄為止)。如果path不存在,或者該目錄不為空,將會產生異常 |
| remove(path) | 刪除path指定的文件。如果path不是一個文件,或者文件不存在,將會產生異常 |
| getcwd() | 返回當前的工作目錄,即以腳本運行文件所在的目錄 |
| chdir(path) | 改變當前的工作目錄,工作目錄由path指定 |
| rename(src,dst) | 重命名一個文件或目錄。src指定源文件的路徑,dst指定重命名后的文件路徑。src與dest要求為同一目錄 |
| renames(old,new) | 與rename相似,但是old與new指定的目錄可以不同(此時類似于移動文件)。在方法執行時,會刪除old路徑中左側所有的非空目錄,并根據需要,創建new路徑中不存在的目錄。在Windows系統,old與new必須在同一盤符中 |
| listdir(path) | 獲取path指定目錄下所有的文件與子目錄名(包括隱藏文件),以列表形式返回。列表元素的順序是沒有任何保證的。如果path為空,則默認為當前目錄 |
| system() | 在shell中執行command指定的命令 |
| sep | 返回特定操作系統使用的分隔符 |
| name | 返回操作系統的名稱。在Windows上返回nt,在Linux上返回posix |
| environ | 返回操作系統的環境變量 |
| linesep | 返回操作系統使用的換行符 |
| pathsep | 返回操作系統環境變量的分隔符 |
| curdir | 返回當前目錄(.) |
| pardir | 返回上級目錄(..) |
2.2 os.path模塊
os.path模塊提供了關于路徑操作的相關功能,常用方法如下:
| 方法名 | 描述 |
| abspath(path) | 返回path的絕對路徑 |
| basename(path) | 返回path的最后一個部分。即path中操作系統分隔符(/或\等)最后一次出現位置后面的內容。如果path以操作系統分隔符結尾,則返回空字符串 |
| commonpath(paths) | 參數paths為路徑的序列,返回最長的公共子路徑 |
| dirname(path) | 返回path的目錄部分 |
| exists(path) | 判斷路徑是否存在,存在返回True,否則返回False |
| getatime(path) | 返回文件或目錄的最后訪問時間 |
| getmtime(path) | 返回文件或目錄的最后修改時間 |
| getsize(path) | 返回文件的大小,以字節為單位 |
| isabs(path) | 判斷path是否為絕對路徑,是返回True,否則返回False |
| isdir(path) | 判斷path是否為存在的目錄,是返回True,否則返回False |
| isfile(path) | 判斷path是否為存在的文件,是返回True,否則返回False |
| join(path,*paths) | 連接所有的path,以當前操作系統的分隔符分隔,并返回。空path(除了最后一個)將會丟棄。如果最后一個path為空,則以分隔符作為結尾。如果其中的一個path為絕對路徑,則絕對路徑之前的路徑都會丟棄,從絕對路徑處開始連接 |
| split(path) | 將path分割成一個元組,元組含有兩個元素,第2個元素為path的最后一個部分,第一個元素為剩余之前的部分。(dirname與basename) |
?
2.3 shutil模塊
shutil模塊提供了高級操作文件的方式。通過該模塊提供的功能,可以快捷方便的對文件或目錄執行復制,移動等操作。常用方法如下:
| 方法名 | 描述 |
| copy(src,dst) | 復制文件,返回復制后的文件路徑。src指定要復制的文件,如果dst是一個存在的目錄,則將文件復制到該目錄中,文件名與src指定的文件名一致,否則,將src復制到dst指定的路徑中,文件名為dst中指定的文件名 |
| copy2(src,dst) | 與copy函數類似,但是copy函數不會保留文件的元信息,例如創建時間,最后修改時間等。copy2函數會盡可能保留文件的元信息 |
| copytree(src,dst) | 復制一個目錄,目錄中的文件與子目錄也會遞歸實現復制,返回復制后的目錄路徑。src指定要復制的目錄,dst指定復制后的目標目錄,如果dst已經存在,則會產生異常 |
| rmtree(path) | 刪除path指定的目錄,目錄中的子目錄與文件也會一并刪除 |
| move(src,path) | 將文件或目錄移動到另外一個位置,src指定文件或目錄的路徑,當src為目錄時,會將該目錄下所有的文件與子目錄一同移動(遞歸)。dst指定移動的目標文件或目錄 |
使用copytree(src,dst)復制目錄時,可以結合ignore_patterns函數對目錄下的文件與子目錄進行排除。如:shutil.copytree("abc", "def", ignore=shutil.ignore_patterns("*.txt"))ignore參數指定忽略的文件或目錄,這樣,所有名稱以txt結尾的文件或目錄將不會復制到目標目錄中。
?
2.4 glob模塊
glob模塊提供列舉目錄下文件的方法,支持通配符*,?與[?]。常用方法如下:
glob(pathname,?*, recursive=False)
返回所有匹配pathname的文件與目錄名稱構成的列表,列表中元素的順序是沒有規律的。如果recursive值為True,則可以使用**匹配所有文件與目錄,包括所有子目錄中的文件與目錄(遞歸)。
pathname中可以指定通配符:①*:匹配任意0個或多個字符②?:匹配任意1個字符③[]:匹配[]內的任意一個字符,支持使用“-”區間的表示。例如[0-9]則匹配0到9任何一個字符,[a-f]則匹配a-f之間的任何一個字符
iglob(pathname, *, recursive=False)與glob功能相同,只是返回一個迭代器而不是列表。
?
3 序列化
3.1 csv
CSV(Comma Separated Values),是一種存文本格式的文件,文件中各個元素值通常使用逗號(,)進行分隔,但這不是必須的,擴展名為.csv。可以使用csv模塊來操作csv類型的文件。
# scv模塊 import csv # 寫入csv文件,在寫入的時候最好將newline設置為"",不然會產生空行 with open("E:/test/a.csv","wt",newline="") as f:# writer函數返回一個寫入器對象,能向參數指定的文件中寫入數據writer = csv.writer(f)writer.writerow(["張三","18","男"])writer.writerow(["李四","20","男"])# 一次寫入多行記錄的話提供一個二維列表,每個一維列表就是一條記錄writer.writerows([["王五","25","男"],["趙六","30","男"]]) # 讀取csv文件 with open("E:/test/a.csv","rt") as f:# reader函數返回一個讀取器對象(是可迭代對象),能夠讀取csv文件中的數據內容reader = csv.reader(f)for lines in reader:print(lines)3.2 json
(1)什么是json
JSON(JavaScript Object Notation),是一種輕量級的數據交換格式。json采用的是一組鍵與值的映射,鍵與值之間使用“:”進行分隔,而鍵值對之間使用“,”進行分隔。json文件中的類型可以是:
| 類型 | 描述 |
| 對象類型 | 使用{}表示 |
| 數組類型 | 使用[]表示 |
| 字符串類型 | 使用雙引號表示 |
| 布爾類型 | true或false |
| 數值類型 | 整數與浮點數 |
格式如下:
{"desc": "json","data": {"content": ["content1", "content2", "content3"],"annotation": "注釋"} }(2)dump與load處理程序,dumps與loads序列化與反序列化
可以通過json類型的數據進行對象的序列化與反序列化。
序列化:將對象類型轉換成字符串的形式。
反序列化:將序列化的字符串恢復為對象類型。
通過序列化與反序列化,我們就可以方便的對復雜的對象進行存儲與恢復(因為文件讀寫只支持字符串類型),或者通過網絡進行傳輸,將對象共享給遠程的其他程序使用。
# json文件提供不同項目之間的數據交換 import json data = {"desc": "json","data": {"content": ["content1", "content2", "content3"],"annotation": "注釋"} } with open("E:/test/a.json","wt") as f:# 向文件中寫入json格式數據,參數1:要寫入的數據,參數2:文件對象# json寫入數據時,默認只顯示ascii字符集的字符,非ascii字符集的字符需要轉義# 指定ensure_ascii=False可以顯示,非ascii字符集的字符json.dump(data,f,ensure_ascii=False) with open("E:/test/a.json","rt") as f:# 讀取json數據,恢復成一個字典data = json.load(f)print(type(data))print(data) # 通過序列化與反序列化,可以實現不同項目之間的數據交換 # 序列化 d = json.dumps(data,ensure_ascii=False) print(type(d)) print(d) # 反序列化 d2 = json.loads(d) print(type(d2)) print(d2)Python中的數據類型與json格式的數據類型并非完全相符,因此,在進行轉換的時候,可能會進行一些映射處理,如下(json?-> Python):
布爾類型(true與false)映射Python中布爾類型(True與False)。
空值類型(null)映射為None。
整數與浮點類型映射為整數(int)與(float)類型。
字符串類型映射為字符串(str)類型。
數組類型([])映射為列表(list)類型。
對象類型(object)映射為字典(dict)類型
# json文件提供不同項目之間的數據交換 import json data = {"布爾類型":False,"空值類型":None,"整數與浮":2,"浮點類型":2.2,"字符串類型":"a","數組類型":[1,2,3],"對象類型":{"a":1,"b":2} } d = json.dumps(data,ensure_ascii=False) print(d) d2 = json.loads(d) print(d2)(3)自定義類型序列化
json在序列化時,不能序列化我們自定義的類型。如果我們需要自定義的類型也能夠序列化,可以定義一個編碼類,該類繼承json.JSONEncoder,實現類中的default方法,指定序列化的方式,同時,在調用序列化方法時(dump或dumps),使用cls參數指定我們定義的編碼類。
# 自定義類型序列化 import json # 自定義的編碼類繼承json.JSONEncoder類型 class StudentEncoder(json.JSONEncoder):# 實現default方法,給出序列化形式,參數o為序列化對象def default(self, o):if isinstance(o,Student):# 將Student轉換成可序列化對象# return {"name":o.name,"age":o.age}# 返回所有屬性構成字典return o.__dict__else:# 不是Student類型,調用父類的default翻翻產生錯誤信息return super().default(0) class Student:def __init__(self,name,age):self.name = nameself.age =age s = Student("refuel",18) print(s.__dict__) # cls參數指定序列化需要用到的編碼類 jsonstr = json.dumps(s,cls=StudentEncoder) print(jsonstr)?
3.3 pickle
pickle模塊也能序列化類型。在序列化自定義類型上,pickle可以比json模塊更加方便(不需要定義類似的編碼器類)。pickle與json在序列化上的區別如下:
| 序列化 | json | pickle |
| 序列化格式 | 文本格式,可進行正常查看。 | 二進制格式,不方便查看。 |
| 序列化類型的支持 | 支持一部分內建的類型,如果需要序列化自定義類型,需要編寫編碼類。 | 支持非常廣泛的類型,包括自定義類型,不需要編寫編碼類。 |
| 適用廣泛性 | 適用廣泛,對于序列化的內容可以用于Python語言之外的程序中進行反序列化。 | 適用受限,只能用于Python程序中,其他語言的程序無法反序列化。 |
4 上下文管理器
4.1 自定義上下文管理器
with語句跟隨的表達式會返回一個上下文管理器,該上下文管理器中定義相關方法,在with開始執行與退出時會調用,也就是說,上下文管理器為with提供一個執行環境。
__enter__(self):with語句體開始執行時,會調用該方法。可以在該方法中執行初始化操作,返回值會賦值給with語句中as后面的變量
__exit__(self, exc_type, exc_val, exc_tb):with語句體執行結束后,會調用該方法。我們在__enter__方法中執行的初始化,就可以在該方法中執行相關的清理,如,文件的關閉,線程鎖的釋等。實現finally語句同樣的功能。exc_type:產生異常的類型;exc_val:產生異常類型的對象;exc_tb:traceback類型的對象,包含了異常產生位置的堆棧調用信息。如果在with語句體中沒有產生異常,相關參數為None。
對于with,也可以關聯兩個上下文管理器,如:
with Manager1() as m1, Manager2 as m2:語句這相當于:with Manager1() as m1:with Manager2() as m2:語句?
class MyManager:def __enter__(self):print("進入with語句體")# return selfreturn "__enter__返回值賦值給as后變量"def __exit__(self, exc_type, exc_val, exc_tb):print("離線with語句體")print(exc_type)print(exc_val)print(exc_tb) with MyManager() as f:# print(f)raise Exception("with中存在異常")4.2?@contextmanager裝飾器
contextlib模塊中,定義了@contextmanager裝飾器,該裝飾器可以用來修飾一個生成器,從而將生成器變成一個上下文管理器,從而可以省略編寫完整的上下文管理器類。
在@contextmanager修飾的生成器中,yield之前的語句會在進入with語句體時執行(相當于__enter__方法),而yield之后的語句會在離開with語句體時執行(相當于__eixt__方法)。
with后的表達式會返回生成器對象(假設為gen_obj),進入with語句體時,內部會調用next函數,用來激活生成器對象,進而執行生成器的函數體next(gen_obj)
從而令生成器對象執行。yield產生的值則會賦值給with語句as后的變量(相當于__enter__方法的返回值)。
當with語句體結束時,如果with語句體沒有產生異常,則繼續調用next,令生成器從之前yield暫停的位置處繼續執行(這相當于實現__exit__方法)。如果with語句體產生異常,該異常會在生成器函數體yield的位置拋出。而如果生成器函數體沒有處理該異常,將會導致yield之后的語句不會得到執行,這相當于是沒有成功的執行__exit__方法。
# @contextManager修飾一個生成器,裝飾成上下文管理器 from contextlib import contextmanager # yield之前的語句會在進入with環境時執行(相當于__enter__方法) # yield產生的值賦值給as后面的變量(相當與__enter__方法的返回值) # 離開with環境,執行yield之后的語句(相當于是__exit__方法) @contextmanager def f():print("進入with環境")# 如果with語句體中產生異常,該異常會傳播到yield位置處,后面的語句不得到執行,# 所以要使用try-finally操作.根據情況捕獲,相當于實現了__exit__方法的返回值try:yield "產生的值賦值給as后面的變量"except:passfinally:print("離開with環境") with f() as f:# print(f)raise Exception("異常")總結
以上是生活随笔為你收集整理的Python基础(十)--文件相关的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql多种join_MySQL的几种
- 下一篇: websocket python爬虫_p