python文件路径操作及pathlib库
對文件的路徑操作是一個非?;A(chǔ)的問題,但也是一個至關(guān)重要的問題,優(yōu)雅的路徑操作不僅可以讓代碼可讀性更高;還可以讓用戶避免很多不必要的麻煩。python中路徑操作常用的幾種方式重要包括:字符串拼接、os.path、以及python 3.4中新增的面向?qū)ο蟮穆窂讲僮鲙?pathlib。
字符串拼接
字符串拼接是最原始、最不優(yōu)雅的路徑操作方式,也是很多初學(xué)者偏愛的方式,但是強烈推薦使用以下兩種更優(yōu)雅的路徑操作方式。因為不推薦字符串拼接,所以下面簡要列舉一下常見的拼接方式(更多字符串操作方法請見Python字符串處理)。
In [2]: directory = '/home/jeffery0207' In [3]: filename = 'a.txt'In [4]: directory + '/' + filename Out[4]: '/home/jeffery0207/a.txt'In [5]: '/'.join([directory, filename]) Out[5]: '/home/jeffery0207/a.txt'In [6]: f'{directory}/{filename}' # python3.6之后新增 Out[6]: '/home/jeffery0207/a.txt'In [7]: '{0}/{1}'.format(directory, filename) Out[7]: '/home/jeffery0207/a.txt'In [8]: '%s/%s' % (directory, filename) Out[8]: '/home/jeffery0207/a.txt'os.path
os.path模塊是個人比較常用的一個模塊,因為Unix系統(tǒng)和windows系統(tǒng)上的路徑表征有一定的差別,加載該模塊時python會自動根據(jù)所使用的的系統(tǒng)加載不同版本的os.path (posixpath對應(yīng)于Unix-style的路徑處理;ntpath對應(yīng)于Windows-style的路徑處理)。該模塊實現(xiàn)了一些實用的路徑處理函數(shù),主要包括:
__all__ = ['expanduser', 'expandvars','abspath', 'realpath', 'relpath','split', 'splitdrive', 'splitext', 'basename', 'dirname', 'join','getatime', 'getctime', 'getmtime', 'getsize','isabs', 'isdir', 'isfile', 'islink', 'ismount', 'exists', 'lexists','samefile', 'sameopenfile', 'samestat','normcase', 'normpath','commonpath', 'commonprefix']-
expanduser() 和 expandvars()函數(shù)
python默認(rèn)不會識別shell變量及家目錄符~,可以通過這兩個函數(shù)實現(xiàn)擴展
In [1]: expandvars('$HOME/workspace') Out[1]: '/home/liunianping/workspace'In [2]: expanduser('~/workspace') Out[2]: '/home/liunianping/workspace' -
split(), splitdrive(), splitext(), basename(), dirname() 和 join()
該模塊中最好用的一組函數(shù),常用于路徑拼接
In [3]: split(path) Out[3]: ('/Users/jeffery0207', 'a.b.c.txt')In [4]: splitext(path) Out[4]: ('/Users/jeffery0207/a.b.c', '.txt')In [5]: splitdrive(path) Out[5]: ('', '/Users/jeffery0207/a.b.c.txt')In [6]: basename(path) Out[6]: 'a.b.c.txt'In [7]: dirname(path) Out[7]: '/Users/jeffery0207'In [8]: join(dirname(path), 'text.txt') Out[8]: '/Users/jeffery0207/text.txt' -
isabs(), isdir(), isfile(), islink(), ismount(), exists(), lexists()
該模塊中用于路徑處理判斷的一組函數(shù)
In [9]: isabs(expanduser('~/.zshrc')),isabs('./.zshrc') # 判斷給定路徑是否是絕對路徑 Out[9]: (True, False)In [11]: isdir('./.local') # 判斷給定路徑是否是文件夾類型 Out[11]: TrueIn [12]: isfile('./.local') # 判斷給定路徑是否是普通文件 Out[12]: FalseIn [13]: islink('./miniconda3/bin/python') # 判斷給定路徑是否是符號鏈接文件 Out[13]: TrueIn [14]: ismount('/media/disk01') # 判斷給定路徑是否是掛載點 Out[14]: TrueIn [15]: exists('./miniconda3/bin/python'), lexists('./miniconda3/bin/python') # 當(dāng)判斷一個鏈接文件是否存在時,如果所鏈接那個文件不存在時,前者返回False,后者返回True Out[15]: (True, True) -
getatime(), getctime(), getmtime()和getsize()
依次指:返回上次訪問該path的時間;返回該path的系統(tǒng)ctime,在unix系統(tǒng)上對應(yīng)于該path上次元數(shù)據(jù)更改的時間,在windows上對應(yīng)文件的創(chuàng)建時間;返回該path上一次修改的時間;返回該path的文件大小
In [16]: path = './.zshrc' In [17]: getatime(path), getctime(path), getmtime(path), getsize(path) Out[17]: (1634019401.9940903, 1633942149.2245831, 1633942149.2205787, 4506) -
normcase(), normpath()
In [18]: normcase(path) # 在windows系統(tǒng)上將所有字符小寫,并將所有正斜杠轉(zhuǎn)換為反斜杠;其他系統(tǒng)返回不變的path Out[18]: './.zshrc'In [19]: join('./a/', './b.txt') Out[19]: './a/./b.txt'In [20]: normpath(join('./a/', './b.txt')) # 折疊多余的分隔符,在這種情況下非常有用 Out[20]: 'a/b.txt' -
commonpath(), commonprefix()
In [27]: commonpath(['./a/b/c.1.txt', './a/b/c.2.txt']) Out[27]: 'a/b'In [28]: commonprefix(['./a/b/c.1.txt', './a/b/c.2.txt']) Out[28]: './a/b/c.' -
samefile(path1, path2),sameopenfile(fp1, fp2) , samestat(stat1, stat2)
我們可以創(chuàng)建如下兩個文件作為演示:
>>> mkdir test && cd test >>> touch a.txt >>> ln -s a.txt a.link.txt >>> ll # lrwxr-xr-x 1 jeffery0207 staff 5B Oct 12 21:47 a.link.txt -> a.txt # -rw-r--r-- 1 jeffery0207 staff 0B Oct 12 21:47 a.txt首先我們需要了解一下另外三個函數(shù),os.fstat(fd), os.lstat(path, *, dir_fd=None), os.stat(path, *, dir_fd=None, follow_symlinks=True):
-
os.stat(path, *, dir_fd=None, follow_symlinks=True)
該函數(shù)返回一個stat_result對象(stat_result詳細(xì)屬性請見os.stat_result),表征一個文件(file)或則文件描述符(file descriptor)的狀態(tài),等效于系統(tǒng)調(diào)用stat:
$ stat a.txt # mac系統(tǒng)的顯示 16777223 12934280785 -rw-r--r-- 1 jeffery staff 0 0 "Oct 12 21:47:10 2021" "Oct 12 21:47:10 2021" "Oct 12 21:47:10 2021" "Oct 12 21:47:10 2021" 4096 0 0 a.txt$ stat a.txt # linux 系統(tǒng)的顯示File: ‘a(chǎn).txt’Size: 4 Blocks: 8 IO Block: 4096 regular file Device: fd0ah/64778d Inode: 69309229738 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 1042/jeffery) Gid: ( 110/ staff) Access: 2021-12-02 22:01:41.000000000 +0800 # 最后訪問時間 Modify: 2021-12-02 22:01:40.000000000 +0800 # 最后修改時間 Change: 2021-12-03 10:10:28.992397846 +0800 # 最后狀態(tài)改變時間 Birth: # 創(chuàng)建時間該函數(shù)默認(rèn)會跟蹤符號鏈接文件,要獲得符號鏈接文件本身的狀態(tài),需要設(shè)置參數(shù)follow_symlinks=False或則使用os.lstat
-
os.lstat(path, *, dir_fd=None)
該函數(shù)返回一個stat_result對象,表征一個文件(file)的狀態(tài)。從python3.3起,os.lstat(path, *, dir_fd=None)函數(shù)等同于os.stat(path, dir_fd=dir_fd, follow_symlinks=False函數(shù)。
-
os.fstat(fd)
該函數(shù)返回一個stat_result對象,表征一個文件描述符(file descriptor)的狀態(tài)。從 Python 3.3 開始,這等效于 os.stat(fd)
samestat(stat1, stat2)檢測兩個stat_result對象是否指向同一個文件:
In [30]: a_link_stat = stat('./test/a.link.txt') In [31]: a_stat = stat('./test/a.txt') In [32]: a_link_lstat = lstat('./test/a.link.txt') In [33]: samestat(a_link_stat, a_stat), samestat(a_link_lstat, a_stat) Out[33]: (True, False)而samefile(path1, path2)函數(shù)即底層調(diào)用os.stat(path, *, dir_fd=None, follow_symlinks=True)檢測兩個文件是否指向同一個文件:
In [34]: samefile('./test/a.link.txt', './test/a.txt') Out[34]: Truesameopenfile(fp1, fp2)則檢測兩個文件描述符是否是指同一個文件,是則返回True,反之返回False。其先通過依次調(diào)用fstat()函數(shù)和samestat()函數(shù)判斷個文件描述符是否是指同一個文件。
In [34]: import os In [35]: fd_a = os.open('./test/a.txt', os.O_RDWR) In [36]: fd_a_link = os.open('./test/a.link.txt', os.O_RDWR) In [37]: sameopenfile(fd_a, fd_a_link) Out[37]: True -
-
abspath(path), relpath(path, start=os.curdir)), realpath(path, *, strict=False)
分別對應(yīng)絕對路徑 (等效于normpath(join(os.getcwd(), path)))、相對路徑(返回path相對于start文件夾的路徑)、真實路徑(該函數(shù)用于解析鏈接文件的真實路徑,當(dāng)strict=False時,如果path不存在或遇到符號鏈接循環(huán)則會拋出OSError錯誤)。
In [39]: abspath(path) Out[39]: '/Users/jeffery/.zshrc'In [40]: relpath(abspath(path), start='./') # start 參數(shù)默認(rèn)值為os.curdir,即當(dāng)前文件夾 Out[40]: '.zshrc'In [41]: realpath('./miniconda3/bin/python') # 一般,我們的python其實是一個鏈接文件,對應(yīng)一個具體的python版本文件 Out[41]: '/Users/jeffery/miniconda3/bin/python3.9'
pathlib
? pathlib是python3.4中新增的面向?qū)ο蟮奈募到y(tǒng)路徑操作模塊,為不同文件系統(tǒng)提供較為統(tǒng)一的文件系統(tǒng)路徑操作方法。該模塊主要定義了以下類(class),其中pure path包括PurePath, PurePosixPath, PureWindowsPath; concrete paths 包括Path,PosixPath以及WindowsPath,其繼承關(guān)系如下圖所示,PurePath 為其他所有類的父類;Path類繼承于PurePath,同時作為PosixPath,WindowsPath的子類。
? 因此,pure paths和concrete paths主要區(qū)別在于Path類的方法,pure paths類主要封裝了對路徑本身的操作,而concrete paths還包括對文件系統(tǒng)地操作,如新建、刪除等。這種繼承關(guān)系可以很好的分離路徑操作和文件系統(tǒng)的操作,更多請參考之前的博客python面向?qū)ο缶幊?/p>
PurePath方法和屬性-路徑操作
| drive | root | anchor | parents |
| name | suffix | suffixes | stem |
| as_uri() | is_absolute() | is_relative_to(*other) | is_reserved() |
| match(pattern) | relative_to(*other)? | with_name(name) | with_stem(stem) |
-
drive
In [5]: p.drive, p2.drive # Unix-style的路徑?jīng)]有盤的概念 Out[5]: ('', 'c:') -
root
In [6]: p.root, p2.root Out[6]: ('/', '\\') -
anchor
In [7]: p1.anchor, p2.anchor # anchor 就是指 drive和root兩者 Out[7]: ('/', 'c:\\') -
parents
該屬性是路徑的所有父目錄,返回一個Iterable對象
In [8]: pars = p.parentsIn [9]: from collections import Iterable In [11]: isinstance(pars, Iterable) Out[11]: TrueIn [12]: for par in pars:...: print(par)...: /Users/jeffery /Users / -
parent
該屬性指路徑的父目錄,p.parent則是/Users/jeffery
-
name
該屬性指路徑最后一層級的名稱,但不包括drive和root,可方便的用于取文件名或文件夾名
In [13]: p1.name Out[13]: 'a.b.c.txt' In [14]: PurePath('/').name Out[14]: '' -
suffix
In [15]: p.suffix # 取文件擴展名 Out[15]: '' In [16]: p1.suffix Out[16]: '.txt' -
suffixes
In [17]: p1.suffixes # 取多層級的文件擴展名,其本質(zhì)就是根據(jù).進(jìn)行字符串分割 Out[17]: ['.b', '.c', '.txt'] -
stem
相當(dāng)于先取path.name,然后再去除文件擴展名(path.suffix)
In [18]: p1.stem Out[18]: 'a.b.c' -
as_posix()
將路徑轉(zhuǎn)換成斜桿/的形式
In [19]: p = PureWindowsPath('c:\\windows') In [20]: str(p) Out[20]: 'c:\\windows' In [21]: p.as_posix() Out[21]: 'c:/windows' -
as_uri()
將路徑轉(zhuǎn)換成文件url的形式,參數(shù)path必須是絕對路徑,否則拋出ValueError
In [22]: p1.as_uri() Out[22]: 'file:///Users/jeffery/a.b.c.txt' -
is_absolute()
判斷一個路徑是否是絕對路徑的形式
-
is_relative_to(*other)
該方法判斷路徑是否和另一個路徑是相對關(guān)系,換句話說就是other是否是路徑的父目錄或則相同目錄(當(dāng)路徑本身是目錄時)
In [26]: p1.is_relative_to('/Users/jeffery') Out[26]: True In [27]: p1.is_relative_to('/Users') Out[27]: True In [28]: p1.is_relative_to('/Users/jeffery/c.txt') Out[28]: False -
is_reserved()
判斷一個目錄是否是操作系統(tǒng)中一些特殊的文件設(shè)備名,如nul, com1, com2等,該命令只針對windows-like path, Posix-like path總是返回False.
In [35]: PureWindowsPath('nul').is_reserved() Out[35]: True -
joinpath(*other)
路徑名連接,等效于操作符/
In [32]: PurePosixPath('/etc').joinpath('init.d', 'apache2') Out[32]: PurePosixPath('/etc/init.d/apache2')In [33]: PurePosixPath('/etc') / 'init.d' / 'apache2' Out[33]: PurePosixPath('/etc/init.d/apache2') -
match(pattern)
路徑名稱匹配
In [34]: PurePath('/a/b/c.py').match('b/*.py') Out[34]: TrueIn [35]: PurePath('/a/b/c.py').match('a/*.py') Out[35]: FalseIn [36]: PurePath('/a/b/c.py').match('/a/*.py') # 特別注意這一點,和shell的匹配模式不一樣 Out[36]: False -
relative_to(*other)?
以other路徑為起點,計算路徑的相對路徑,如果無法計算則拋出ValueError
In [39]: p.relative_to('/') Out[39]: PurePosixPath('etc/passwd')In [40]: p.relative_to('/etc/passwd') Out[40]: PurePosixPath('.')以上代碼等效于os.path.relpath:
In [42]: from os.path import relpath In [43]: relpath('/etc/passwd', start='/') Out[43]: 'etc/passwd' In [44]: relpath('/etc/passwd', start='/etc/passwd') Out[44]: '.' -
with_name(name)
該方法將路徑中原本的name替換為新的name,如果路勁中本身不存在name,則拋出ValueError錯誤
In [45]: p1.with_name('new.txt') Out[45]: PurePosixPath('/Users/jeffery/new.txt')## 用os.path實現(xiàn) In [46]: from os.path import join, split In [47]: join(split('/Users/jeffery/a.b.c.txt')[0], 'new.txt') Out[47]: '/Users/jeffery/new.txt' -
with_stem(stem)
該方法將路徑中原本的stem替換為新的stem,如果路勁中本身不存在name,則拋出ValueError錯誤
In [51]: p1.with_stem('new') Out[51]: PurePosixPath('/Users/jeffery/new.txt')## 用os.path實現(xiàn) In [52]: from os.path import join, split, splitext In [53]: join(split("/Users/jeffery/a.b.c.txt")[0],'new' + splitext("/Users/jeffery/a.b.c.txt")[1]) Out[53]: '/Users/jeffery/new.txt' -
with_suffix(suffix)
該方法將路徑中原本的suffix替換為新的suffix,如果suffix="",則原本的suffix直接移除
In [54]: p1.with_suffix('.py') Out[54]: PurePosixPath('/Users/jeffery/a.b.c.py')
ConcretePath方法和屬性-文件系統(tǒng)操作
| cwd() | home() | stat(*,follow_symlinks=True) | chmod(mode,*,follow_symlinks=True) |
| expanduser() | glob(pattern) | group() | is_dir() |
| is_mount() | is_symlink() | is_socket() | is_fifo() |
| is_char_device() | iterdir() | lchmod(mode) | lstat() |
| open(mode=‘r’,buffering=-1,encoding=None,errors=None,newline=None) | owner() | read_bytes() | read_text(encoding=None,errors=None) |
| rename(target) | replace(target) | resolve(strict=False) | rglob(pattern) |
| samefile(other_path) | symlink_to(target,target_is_directory=False) | hardlink_to(target) | link_to(target) |
| unlink(missing_ok=False) | write_bytes(data) | write_text(data,encoding=None,errors=None,newline=None) |
為了探索ConcretePath方法和屬性,我們首先在家目錄下建一個新的文件tmp, 并在tmp下新建文件a.txt。
In [1]: from pathlib import PosixPath, Path, WindowsPathIn [2]: p1 = PosixPath('./tmp')In [3]: p2 = Path('./tmp/a.txt')-
cwd()
該方法返回當(dāng)前所在文件夾,等同于os.getcwd(),因此可以知道該方法應(yīng)該是一個classmethod,其調(diào)用與具體的對象無關(guān)
In [4]: Path.cwd(), PosixPath.home() Out[4]: (PosixPath('/Users/jeffery'), PosixPath('/Users/jeffery')) -
home()
該方法也是一個classmethod,返回用戶的家目錄路徑,等同于os.path.expanduser()
-
stat(*, follow_symlinks=True)
該方法類似于前面介紹的os.stat(),返回一個os.stat_result對象(stat_result詳細(xì)屬性請見os.stat_result)。所以,類似的,follow_symlinks=False時,可以統(tǒng)計鏈接文件的信息, 等效于os.lstat。
In [5]: stat_result = p2.stat()In [6]: stat_result Out[6]: os.stat_result(st_mode=33188, st_ino=12936268394, st_dev=16777223, st_nlink=1, st_uid=501, st_gid=20, st_size=15, st_atime=1637994757, st_mtime=1637994751, st_ctime=1637994751) -
chmod(mode, *, follow_symlinks=True)
修改路徑權(quán)限,類似于os.chmod()或則shell 命令chmod。這里我們使用
In [10]: p2.chmod(0o655) # (python3)這里使用8進(jìn)制,更為簡明 In [11]: ll tmp/ -rw-r-xr-x 1 jeffery staff 15 Nov 27 14:32 a.txt -
exists()
判斷路徑是否存在,值得注意的是,當(dāng)路徑是鏈接文件時,該方法會進(jìn)一步追蹤查看對應(yīng)的符號鏈接是否存在
-
expanduser()
同上面的os.path.expanduser(),如果家目錄無法確定的話,則拋出RuntimeError
-
glob(pattern)
根據(jù)pattern搜索路徑中匹配的文件,pattern的匹配規(guī)則同fnmatch,主要利用以下unix shell-like通配符進(jìn)行簡單的文件匹配任務(wù)(如更復(fù)雜的任務(wù),請參考python re 正則表達(dá)式):
PatternMeaning * matches everything ? matches any single character [seq] matches any character in seq [!seq] matches any character not in seq glob(pattern)方法返回一個generator類型,可以通過迭代的方法取出所有匹配的文件:
In [13]: g = p1.glob('*.txt')In [14]: for _g in g:...: print(_g)...: tmp/a.txtIn [15]: type(g) Out[15]: generatorpython標(biāo)準(zhǔn)庫glob中g(shù)lob.glob()及glob.iglob()函數(shù)也是利用unix shell-like 通配符進(jìn)行文件匹配。前者返回數(shù)據(jù)類型為list,后者返回類型為iterator。
In [16]: from glob import glob, iglob, escape In [17]: glob('./tmp/*.txt') Out[17]: ['./tmp/a.txt'] In [18]: iglob('./tmp/*.txt') Out[18]: <generator object _iglob at 0x110e8e510>需要注意的是,glob.glob()默認(rèn)情況下是不會匹配隱藏文件的;而Path.glob()會匹配隱藏文件:
In [19]: for _g in p1.glob('*.txt'):...: print(_g)...: tmp/.a.txt tmp/a.txtIn [20]: glob('./tmp/*.txt') Out[20]: ['./tmp/a.txt']另外,當(dāng)文件匹配的路徑中含有通配符時,我們可以借助glob.escape()函數(shù)進(jìn)行快速注釋,比如我們新建文件mkdir -p "./tmp/[ABC]/b.txt",則我們需要利用以下方式進(jìn)行匹配:
In [21]: from os.path import joinIn [22]: glob(join(escape('./tmp/[ABC]'), '*.txt')) Out[22]: ['./tmp/[ABC]/b.txt'] -
group()
返回文件所屬組別
-
is_dir()
判斷路徑是否是文件夾,返回bool值;需要注意的是如果文件不存在或符號鏈接文件有問題時,也返回False(以下類似函數(shù)也適用該規(guī)則)。
-
is_file()
判斷路徑是否是文件,返回bool值
-
is_mount()
判斷路徑是否是掛載點,返回bool值
-
is_symlink()
判斷路徑是否是符號鏈接文件,返回bool值
-
is_socket()
判斷路徑是否是socket連接,返回bool值
-
is_fifo()
判斷路徑是否是FIFO管道文件,返回bool值
-
is_block_device()
判斷路徑是否是塊設(shè)備文件,返回bool值
-
is_char_device()
判斷路徑是否是字符設(shè)備文件,返回bool值
-
iterdir()
遍歷文件夾,并返回路徑中所有的文件
In [23]: for _dir in p1.iterdir():...: print(_dir)...: tmp/.a.txt tmp/a.txt tmp/[ABC] -
lchmod(mode)
不同于Path.chmod(mode)默認(rèn)效果,該函數(shù)修改文件權(quán)限時,如果路徑是鏈接文件,不會同時修改對應(yīng)符號鏈接文件的權(quán)限
-
lstat()
不同于Path.stat(),當(dāng)路徑是鏈接文件時,返回鏈接文件的統(tǒng)計信息而非它的目標(biāo)文件
-
mkdir(mode=511, parents=False, exist_ok=False)
創(chuàng)建文件夾
-
open(mode=‘r’, buffering=- 1, encoding=None, errors=None, newline=None)
打開文件,類似于python內(nèi)置函數(shù)open()
-
owner()
返回路徑所屬用戶
-
read_bytes()
讀取bytes,相當(dāng)于打開并讀取兩步操作
In [24]: p2.read_bytes() Out[24]: b'This is a bird\n'In [25]: open('./tmp/a.txt', 'rb').read() Out[25]: b'This is a bird\n' -
read_text(encoding=None, errors=None)
類似于read_bytes(),但是以text形式讀取文件
-
readlink()
該方法返回路徑的目標(biāo)鏈接文件,如果路徑不是鏈接文件,則拋出OSError
In [56]: ll ./tmp/ # 命令行新建文件a.link.txt ln -s a.txt a.link.txt total 8 drwxr-xr-x 3 jeffery staff 96 Nov 30 11:27 [ABC]/ lrwxr-xr-x 1 jeffery staff 5 Nov 30 15:03 a.link.txt@ -> a.txt -rw-r-xr-x 1 jeffery staff 15 Nov 30 11:16 a.txt*In [54]: Path('./tmp/a.link.txt').readlink() Out[54]: PosixPath('a.txt') -
rename(target)
重命名文件,返回值為更新后指向target的對象,如果target所對應(yīng)的路徑已經(jīng)存在,在權(quán)限允許下,會直接覆蓋。target參數(shù)既可以是字符串類型也可以是path對象。
target參數(shù)可以是相對路徑,也可以是絕對路徑;當(dāng)相對路徑時,相對的是Path.cwd()而不是path 對象。
In [55]: p = Path('foo')In [56]: p.open('w').write('some text') Out[56]: 9In [57]: target = Path('bar')In [58]: p.rename(target) Out[58]: PosixPath('bar')In [59]: target.open().read() Out[59]: 'some text' -
replace(target)
同上,重命名文件,返回值為更新后指向target的對象。如果target對象已經(jīng)存在,則會無條件的覆蓋
-
resolve(strict=False)
返回路徑的絕對路徑,如果路徑是鏈接文件,則返回路徑對應(yīng)符號鏈接文件的絕對路徑
In [60]: p2.resolve() Out[60]: PosixPath('/Users/jeffery/tmp/a.txt')In [61]: Path('./tmp/a.link.txt').resolve() Out[61]: PosixPath('/Users/jeffery/tmp/a.txt')strict=False時,如果文件不存在,它也會強行解析出其路徑;strict=True時,如果文件不存在,則拋出FileNotFoundError錯誤
In [62]: Path('./tmp/text.txt.zip').resolve() Out[62]: PosixPath('/Users/jeffery/tmp/text.txt.zip')In [63]: Path('./tmp/text.txt.zip').resolve(strict=True) FileNotFoundError: [Errno 2] No such file or directory: '/Users/jeffery/tmp/text.txt.zip' -
rglob(pattern)
該方法等同于Path.glob("**/{pattern}")
-
rmdir()
刪除文件夾,文件夾必須為空
-
samefile(other_path)
返回bool值,判斷路徑與other_path是否指向同一個文件。如果任一文件不存在或權(quán)限問題而無法訪問,則拋出OSError。該方法類似于上面探討到的os.path.samefile() 和 os.path.samestat()。
-
symlink_to(target, target_is_directory=False)
該方法鏈接路徑到target路徑,當(dāng)target是文件夾時,在windows下需要設(shè)置target_is_directory=True; 在unix環(huán)境下,該參數(shù)是忽略的。
In [64]: Path('./tmp/link.txt').symlink_to('./tmp/a.txt')-rw-r-xr-x 1 jeffery staff 15B Nov 30 11:16 a.txt lrwxr-xr-x 1 jeffery staff 11B Dec 2 21:43 link.txt -> ./tmp/a.txt -
hardlink_to(target)
類似于symlink_to(),該方法創(chuàng)建硬鏈接
-
link_to(target)
與hardlink_to()相反,該方法中target作為硬鏈接文件鏈接到對象對應(yīng)路徑
In [65]: p2.link_to('./tmp/hard.link.txt')-rw-r-xr-x 2 jeffery staff 15B Nov 30 11:16 a.txt -rw-r-xr-x 2 jeffery staff 15B Nov 30 11:16 hard.link.txt -
touch(mode=438, exist_ok=True)
創(chuàng)建文件,當(dāng)exist_ok=True且對應(yīng)文件已存在時,會拋出FileExistsError。
-
unlink(missing_ok=False)
刪除文件或移除符號鏈接文件,當(dāng)missing_ok=False且路徑不存在時,拋出FileNotFoundError
-
write_bytes(data)
read_bytes反操作,寫入bytes,相當(dāng)于打開并寫入bytes兩步操作
In [66]: p2.write_bytes(b'xxxx') # 覆蓋式寫入 Out[66]: 4 -
write_text(data, encoding=None, errors=None, newline=None)
類似于write_bytes,但是以text形式寫入文件
對照表
python documentation官方網(wǎng)站也給出了pathlib庫與os及os.path模塊實現(xiàn)相同功能函數(shù)的對照表如下,如果你已經(jīng)熟悉后者,可以依據(jù)該表格快速的進(jìn)行”遷移學(xué)習(xí)“。
| os.path.abspath() | Path.resolve() |
| os.chmod() | Path.chmod() |
| os.mkdir() | Path.mkdir() |
| os.makedirs() | Path.mkdir() |
| os.rename() | Path.rename() |
| os.replace() | Path.replace() |
| os.rmdir() | Path.rmdir() |
| os.remove(), os.unlink() | Path.unlink() |
| os.getcwd() | Path.cwd() |
| os.path.exists() | Path.exists() |
| os.path.expanduser() | Path.expanduser() and Path.home() |
| os.listdir() | Path.iterdir() |
| os.path.isdir() | Path.is_dir() |
| os.path.isfile() | Path.is_file() |
| os.path.islink() | Path.is_symlink() |
| os.link() | Path.hardlink_to() |
| os.symlink() | Path.symlink_to() |
| os.readlink() | Path.readlink() |
| os.path.relpath() | Path.relative_to() 2 |
| os.stat() | Path.stat(), Path.owner(), Path.group() |
| os.path.isabs() | PurePath.is_absolute() |
| os.path.join() | PurePath.joinpath() |
| os.path.basename() | PurePath.name |
| os.path.dirname() | PurePath.parent |
| os.path.samefile() | Path.samefile() |
| os.path.splitext() | PurePath.suffix |
權(quán)限碼轉(zhuǎn)換
前面有個例子,涉及到python中權(quán)限編碼的問題,這里進(jìn)一步展開開探討一下:
In [1]: from pathlib import PathIn [2]: p = Path('./tmp/a.txt')In [3]: sr =p.stat()In [4]: sr Out[4]: os.stat_result(st_mode=33188, st_ino=12936268394, st_dev=16777223, st_nlink=1, st_uid=501, st_gid=20, st_size=4, st_atime=1638497905, st_mtime=1638453700, st_ctime=1638497208)在命令行中,我們同樣可以查看到文件的權(quán)限詳情:
$ ll a.txt -rw-r--r-- 1 jeffery staff 4B Dec 2 22:01 a.txt那么問題來了,st_mode=33188和-rw-r--r--;以及st_mode=33188和644具有怎樣的對應(yīng)關(guān)系呢?
首先,我們可以利用標(biāo)準(zhǔn)庫stat模塊中的``函數(shù)進(jìn)行轉(zhuǎn)換:
In [5]: import stat In [6]: stat.filemode(stat_result.st_mode) # 33188 代表的權(quán)限就是644 Out[6]: '-rw-r--r--'但是st_mode=33188包含的信息其實不僅僅包括文件讀寫權(quán)限的信息:
In [5]: oct(sr.st_mode) # 轉(zhuǎn)換成八進(jìn)制,我們注意到八進(jìn)制包含644,其實八進(jìn)制最后三位對應(yīng)的就是文件的讀寫權(quán)限編碼 Out[5]: '0o100644'st_mode=33188是一個十進(jìn)制數(shù),轉(zhuǎn)換成八進(jìn)制后,我們注意到八進(jìn)制包含644,其實八進(jìn)制最后三位對應(yīng)的正是文件的讀寫權(quán)限編碼,stat.filemode()正是利用該特性進(jìn)行權(quán)限字符串轉(zhuǎn)換的,規(guī)則如下:
S_IRWXU 00700 mask for file owner permissions S_IRUSR 00400 owner has read permission S_IWUSR 00200 owner has write permission S_IXUSR 00100 owner has execute permission S_IRWXG 00070 mask for group permissions S_IRGRP 00040 group has read permission S_IWGRP 00020 group has write permission S_IXGRP 00010 group has execute permission S_IRWXO 00007 mask for permissions for others (not in group) S_IROTH 00004 others have read permission S_IWOTH 00002 others have write permission S_IXOTH 00001 others have execute permission而'0o100644'前面的部分0100000代表的則是文件類型—regular file,具體規(guī)則如下:
S_IFMT 0170000 bitmask for the file type bitfields S_IFSOCK 0140000 socket S_IFLNK 0120000 symbolic link S_IFREG 0100000 regular file S_IFBLK 0060000 block device S_IFDIR 0040000 directory S_IFCHR 0020000 character device S_IFIFO 0010000 FIFO S_ISUID 0004000 set UID bit S_ISGID 0002000 set-group-ID bit S_ISVTX 0001000 sticky bit寫在篇后
這篇博客內(nèi)容本身非常簡單,但是所提到的兩個模塊包含了大量的API,需要我們在日常的使用中靈活應(yīng)用,選擇最高效、優(yōu)雅的方式。其中,pathlib模塊面向?qū)ο缶幊痰穆窂教幚矸绞?#xff0c;能夠非常從容的應(yīng)對較大的項目開發(fā)需求,高度統(tǒng)一路徑操作、文件系統(tǒng)操作,比如單細(xì)胞轉(zhuǎn)錄組分析分析軟件scanpy中便是采用了pathlib庫進(jìn)行路徑處理工作,是項目開發(fā)中不可多得的好例子。
參考資料
python pathlib
python stat
get unix permission mask
總結(jié)
以上是生活随笔為你收集整理的python文件路径操作及pathlib库的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python导入机制及importlib
- 下一篇: R语言稀疏矩阵详解