十年網(wǎng)站開(kāi)發(fā)經(jīng)驗(yàn) + 多家企業(yè)客戶(hù) + 靠譜的建站團(tuán)隊(duì)
量身定制 + 運(yùn)營(yíng)維護(hù)+專(zhuān)業(yè)推廣+無(wú)憂(yōu)售后,網(wǎng)站問(wèn)題一站解決
創(chuàng)新互聯(lián)www.cdcxhl.cn八線(xiàn)動(dòng)態(tài)BGP香港云服務(wù)器提供商,新人活動(dòng)買(mǎi)多久送多久,劃算不套路!
這篇文章將為大家詳細(xì)講解有關(guān)Python3文件操作中是如何使用pathlib模塊的,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
在本教程中,你將了解如何使用 pathlib 模塊操作目錄和文件的名稱(chēng)。學(xué)習(xí)如何讀取和寫(xiě)入文件,拼接路徑和操作底層文件系統(tǒng)的新方法,以及如何列出文件并迭代它們的一些示例。
大多人處理文件用的最多的還是 os 模快吧,比如下面這樣的操作:
>>> path.rsplit('\\', maxsplit=1)[0]
或者寫(xiě)出下面這樣長(zhǎng)長(zhǎng)的代碼
>>> os.path.isfile(os.path.join(os.path.expanduser('~'), 'realpython.txt'))
使用 pathlib 模塊,可以使代碼使用優(yōu)雅,可讀和 Pythonic 代碼重寫(xiě)上面的兩個(gè)示例,如:
>>> path.parent >>> (pathlib.Path.home() / 'realpython.txt').is_file()
Python 文件路徑處理問(wèn)題
由于許多不同的原因,使用文件和與文件系統(tǒng)交互很重要。 最簡(jiǎn)單的情況可能只涉及讀取或?qū)懭胛募?,但有時(shí)候會(huì)有更復(fù)雜的任務(wù)。也許你需要列出給定類(lèi)型的目錄中的所有文件,查找給定文件的父目錄,或者創(chuàng)建一個(gè)尚不存在的唯一文件名。
一般情況,Python 使用常規(guī)文本字符串表示文件路徑。一般在使用 os,glob 和 shutil 等庫(kù)的時(shí)候會(huì)使用到路徑拼接的操作,使用os模塊拼接起來(lái)顯得略顯復(fù)雜,以下示例僅需要三個(gè) import 語(yǔ)句來(lái)將所有文本文件移動(dòng)到歸檔目錄:
import glob import os import shutil for file_name in glob.glob('*.txt'): new_path = os.path.join('archive', file_name) shutil.move(file_name, new_path)
使用常規(guī)的字符串去拼接路徑是可以的,但是由于不同的操作系統(tǒng)使用的分隔符不同,這樣就容易出現(xiàn)問(wèn)題,所以一般我們使用最多的還是使用 os.path.join()。
Python 3.4 中引入了 pathlib 模塊(PEP 428)再一次的優(yōu)化了路徑的拼接。使用 pathlib 庫(kù)的 Path 方法,可以將一個(gè)普通的字符串轉(zhuǎn)換為 pathlib.Path 對(duì)象類(lèi)型的路徑。
早期,其他軟件包仍然使用字符串作為文件路徑,但從 Python 3.6 開(kāi)始,pathlib 模塊在整個(gè)標(biāo)準(zhǔn)庫(kù)中得到支持,部分原因是由于增加了文件系統(tǒng)路徑協(xié)議。 如果你堅(jiān)持使用傳統(tǒng)的 Python,那么 Python 2 也有一個(gè)可用的向后移植。
ok,說(shuō)了那么多下面讓我們看看 pathlib 如何在實(shí)踐中發(fā)揮作用。
創(chuàng)建路徑
這里我們首先要知道兩個(gè)用法,先看代碼:
from pathlib import Path
你真正需要知道的是 pathlib.Path 類(lèi)。創(chuàng)建路徑有幾種不同的方式。首先,有類(lèi)方法,如 .cwd(當(dāng)前工作目錄)和 .home(用戶(hù)的主目錄):
from pathlib import Path now_path = Path.cwd() home_path = Path.home() print("當(dāng)前工作目錄",now_path,type(now_path)) print("home目錄",home_path,type(home_path))
輸出內(nèi)容:
當(dāng)前工作目錄 /Users/chennan/pythonproject/demohome目錄 /Users/chennan
可以發(fā)現(xiàn)路徑格式為 pathlib.PosixPath 這是在 unix 系統(tǒng)下的顯示。在不同的系統(tǒng)上顯示的格式也是不一樣,在 windows 系統(tǒng)會(huì)顯示為 WindowsPath。但是不管什么顯示類(lèi)型,都不影響后面的操作。
前面我們提到過(guò)可以通過(guò)把字符串類(lèi)型的路徑,轉(zhuǎn)換為 Pathlib.Path 類(lèi)型的路徑,經(jīng)過(guò)測(cè)試發(fā)現(xiàn)在 Python3.4 以后很多模塊以及支持該格式的路徑。不用轉(zhuǎn)為成字符串使用了。比起 os.path.join 拼接路徑的方式,pathlib 使用起來(lái)更加的方便,使用示例如下:
import pathlib DIR_PATH = pathlib.Path("/Users/chennan/CDM") print(DIR_PATH,type(DIR_PATH))
輸出內(nèi)容:
/Users/chennan/CDM
通過(guò) “/” 我們就可以對(duì)路徑進(jìn)行拼接了,怎么樣是不是很方便呢。
讀文件和寫(xiě)文件
在我們使用 open 來(lái)操作文件讀寫(xiě)操作的時(shí)候,不僅可以使用字符串格式的路徑,對(duì)于 pathlib 生成的路徑完全可以直接使用:
path = pathlib.Path.cwd() / 'test.md' with open(path, mode='r') as fid: headers = [line.strip() for line in fid if line.startswith('#')] print('\n'.join(headers))
或者在 pathlib 的基礎(chǔ)使用 open,我們推薦使用下面的方式:
import pathlib DIR_PATH = pathlib.Path("/Users/chennan/CDM") / "2000" / "hehe.txt" with DIR_PATH.open("r") as fs: data = fs.read() print(data)
這樣寫(xiě)的好處就是 open 里面我們不需要再去傳入路徑了,直接指定文件讀寫(xiě)模式即可。實(shí)際上這里的 open 方法,底層也是調(diào)用了 os.open 的方法。使用哪種方式看個(gè)人的喜好。
pathlib 還提供幾種文件的讀寫(xiě)方式:
可以不用再使用 with open 的形式即可以進(jìn)行讀寫(xiě)。
.read_text(): 找到對(duì)應(yīng)的路徑然后打開(kāi)文件,讀成str格式。等同open操作文件的"r"格式。 .read_bytes(): 讀取字節(jié)流的方式。等同open操作文件的"rb"格式。 .write_text(): 文件的寫(xiě)的操作,等同open操作文件的"w"格式。 .write_bytes(): 文件的寫(xiě)的操作,等同open操作文件的"wb"格式。
使用 resolve 可以通過(guò)傳入文件名,來(lái)返回文件的完整路徑,使用方式如下:
import pathlib py_path =pathlib.Path("superdemo.py") print(py_path.resolve())
輸出:
/Users/chennan/pythonproject/demo/superdemo.py
需要注意的是 “superdemo.py” 文件要和我當(dāng)前的程序文件在同一級(jí)目錄。
選擇路徑的不同組成部分
pathlib 還提供了很多路徑操作的屬性,這些屬性可以選擇路徑的不用部位,如:
.name: 可以獲取文件的名字,包含拓展名。
.parent: 返回上級(jí)文件夾的名字。
.stem: 獲取文件名不包含拓展名。
.suffix: 獲取文件的拓展名。
.anchor: 類(lèi)似盤(pán)符的一個(gè)東西。
import pathlib now_path = pathlib.Path.cwd() / "demo.txt" print("name",now_path.name) print("stem",now_path.stem) print("suffix",now_path.suffix) print("parent",now_path.parent) print("anchor",now_path.anchor)
輸出內(nèi)容如下:
name demo.txt stem demo suffix .txt parent /Users/chennan/pythonproject/demo anchor /
移動(dòng)和刪除文件
當(dāng)然 pathlib 還可以支持文件其他操作,像移動(dòng),更新,甚至刪除文件,但是使用這些方法的時(shí)候要小心因?yàn)?,使用過(guò)程不用有任何的錯(cuò)誤提示即使文件不存在也不會(huì)出現(xiàn)等待的情況。
使用 replace 方法可以移動(dòng)文件,如果文件存在則會(huì)覆蓋。為避免文件可能被覆蓋,最簡(jiǎn)單的方法是在替換之前測(cè)試目標(biāo)是否存在。
import pathlib destination = pathlib.Path.cwd() / "target" source = pathlib.Path.cwd() / "demo.txt" if not destination.exists(): source.replace(destination)
但是上面的方法存在問(wèn)題就是,在多個(gè)進(jìn)程多 destination 進(jìn)行的操作的時(shí)候就會(huì)現(xiàn)問(wèn)題,可以使用下面的方法避免這個(gè)問(wèn)題。也就是說(shuō)上面的方法適合單個(gè)文件的操作。
import pathlib destination = pathlib.Path.cwd() / "target" source = pathlib.Path.cwd() / "demo.txt" with destination.open(mode='xb') as fid: #xb表示文件不存在才操作 fid.write(source.read_bytes())
當(dāng) destination文件存在的時(shí)候上面的代碼就會(huì)出現(xiàn) FileExistsError 異常。
從技術(shù)上講,這會(huì)復(fù)制一個(gè)文件。 要執(zhí)行移動(dòng),只需在復(fù)制完成后刪除源即可。
使用 with_name 和 with.shuffix 可以修改文件名字或者后綴。
import pathlib source = pathlib.Path.cwd() / "demo.py" source.replace(source.with_suffix(".txt")) #修改后綴并移動(dòng)文件,即重命名
可以使用 .rmdir() 和 .unlink() 來(lái)刪除文件。
import pathlib destination = pathlib.Path.cwd() / "target" source = pathlib.Path.cwd() / "demo.txt" source.unlink()
幾個(gè) pathlib 的使用例子
統(tǒng)計(jì)文件個(gè)數(shù)
我們可以使用.iterdir方法獲取當(dāng)前文件下的所以文件.
import pathlib from collections import Counter now_path = pathlib.Path.cwd() gen = (i.suffix for i in now_path.iterdir()) print(Counter(gen))
輸出內(nèi)容:
Counter({'.py': 16, '': 11, '.txt': 1, '.png': 1, '.csv': 1})
通過(guò)配合使用 collections 模塊的 Counter 方法,我們獲取了當(dāng)文件夾下文件類(lèi)型情況。
前面我們說(shuō)過(guò) glob 模塊點(diǎn)這里了解【cnblogs.com/c-x-a/p/926】,同樣的 pathlib 也有 glob 方法和 rglob 方法,不同的是 glob 模塊里的 glob 方法結(jié)果是列表形式的,iglob 是生成器類(lèi)型,在這里 pathlib 的 glob 模塊返回的是生成器類(lèi)型,然后 pathlib 還有一個(gè)支持遞歸操作的 rglob 方法。
下面的這個(gè)操作我通過(guò)使用 glob 方法,設(shè)定規(guī)則進(jìn)行文件的匹配。
import pathlib from collections import Counter gen =(p.suffix for p in pathlib.Path.cwd().glob('*.py')) print(Counter(gen))
展示目錄樹(shù)
下一個(gè)示例定義了一個(gè)函數(shù) tree(),該函數(shù)的作用是打印一個(gè)表示文件層次結(jié)構(gòu)的可視樹(shù),該樹(shù)以一個(gè)給定目錄為根。因?yàn)橄肓谐銎渥幽夸?,所以我們要使?.rglob() 方法:
import pathlib from collections import Counter def tree(directory): print(f'+ {directory}') for path in sorted(directory.rglob('*')): depth = len(path.relative_to(directory).parts) spacer = ' ' * depth print(f'{spacer}+ {path.name}') now_path = pathlib.Path.cwd() if __name__ == '__main__': tree(now_path)
其中 relative_to 的方法的作用是返回 path 相對(duì)于 directory 的路徑。
parts 方法可以返回路徑的各部分。例如:
import pathlib now_path = pathlib.Path.cwd() if __name__ == '__main__': print(now_path.parts)
返回:
('/', 'Users', 'chennan', 'pythonproject', 'demo')
獲取文件最后一次修改時(shí)間
iterdir(),.glob()和.rglob()方法非常適合于生成器表達(dá)式和列表理解。
使用stat()方法可以獲取文件的一些基本信息,使用.stat().st_mtime可以獲取文件最后一次修改的信息
import pathlib now_path = pathlib.Path.cwd() from datetime import datetime time, file_path = max((f.stat().st_mtime, f) for f in now_path.iterdir()) print(datetime.fromtimestamp(time), file_path)
甚至可以使用類(lèi)似的表達(dá)式獲取上次修改的文件內(nèi)容
import pathlib from datetime import datetime now_path =pathlib.Path.cwd() result = max((f.stat().st_mtime, f) for f in now_path.iterdir())[1] print(result.read_text())
.stat().st_mtime 會(huì)返回文件的時(shí)間戳,可以使用 datetime 或者 time 模塊對(duì)時(shí)間格式進(jìn)行進(jìn)一步轉(zhuǎn)換。
其他內(nèi)容
關(guān)于 pathlib.Path 格式路徑轉(zhuǎn)換為字符串類(lèi)型
因?yàn)橥ㄟ^(guò) pathlib 模塊操作生成的路徑,不能直接應(yīng)用字符串的一些操作,所以需要轉(zhuǎn)換成字符串,雖然可以使用 str() 函數(shù)進(jìn)行轉(zhuǎn)換,但是安全性不高,建議使用 os.fspath() 方法,因?yàn)槿绻窂礁袷椒欠ǖ?,可以?huà)伋鲆粋€(gè)異常。str()就不能做到這一點(diǎn)。
拼接符號(hào)”/”背后的秘密
/ 運(yùn)算符由 __truediv__ 方法定義。 實(shí)際上,如果你看一下 pathlib 的源代碼,你會(huì)看到類(lèi)似的東西。
class PurePath(object): def __truediv__(self, key): return self._make_child((key,))
關(guān)于Python3文件操作中是如何使用pathlib模塊的就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。