每週一個 Python 模組 | os.path
專欄地址:每週一個 Python 模組
本文基於 Python3 編寫測試。
os.path
模組是跨平臺的,即使不打算在平臺之間移植自己的程式也應該用os.path
,好處多多。
解析路徑
第一組os.path
函式可用於將表示檔名的字串解析為其組成部分。重要的是要意識到這些功能不依賴於實際存在的路徑。
路徑解析取決於以下定義的一些os
變數:
-
os.sep
- 路徑部分之間的分隔符(例如,“/
”或“\
”)。 -
os.extsep
- 檔名和檔案“副檔名”之間的分隔符(例如,“.
”)。 -
os.pardir
- 路徑元件,意味著將目錄樹向上遍歷一級(例如,“..
”)。 -
os.curdir
- 引用當前目錄的路徑元件(例如,“.
”)。
split()
函式將路徑分成兩個獨立的部分,並返回一個tuple
結果。第二個元素是路徑的最後一個元素,第一個元素是它之前的所有元素。
import os.path PATHS = [ '/one/two/three', '/one/two/three/', '/', '.', '', ] for path in PATHS: print('{!r:>17} : {}'.format(path, os.path.split(path))) # output # '/one/two/three' : ('/one/two', 'three') # '/one/two/three/' : ('/one/two/three', '') #'/' : ('/', '') #'.' : ('', '.') #'' : ('', '')
當輸入引數以os.sep
結束時,路徑的最後一個元素是一個空字串。
basename()
函式返回一個等於split()
返回值的第二部分的值。
import os.path PATHS = [ '/one/two/three', '/one/two/three/', '/', '.', '', ] for path in PATHS: print('{!r:>17} : {!r}'.format(path, os.path.basename(path))) # output # '/one/two/three' : 'three' # '/one/two/three/' : '' #'/' : '' #'.' : '.' #'' : ''
完整路徑被剝離到最後一個元素,無論是指檔案還是目錄。
dirname()
函式返回拆分路徑的第一部分:
import os.path PATHS = [ '/one/two/three', '/one/two/three/', '/', '.', '', ] for path in PATHS: print('{!r:>17} : {!r}'.format(path, os.path.dirname(path))) # output # '/one/two/three' : '/one/two' # '/one/two/three/' : '/one/two/three' #'/' : '/' #'.' : '' #'' : ''
結合basename()
和dirname()
的結果可以返回原始路徑。
splitext()
類似於split()
,但在擴充套件分隔符上劃分路徑,而不是目錄分隔符。
import os.path PATHS = [ 'filename.txt', 'filename', '/path/to/filename.txt', '/', '', 'my-archive.tar.gz', 'no-extension.', ] for path in PATHS: print('{!r:>21} : {!r}'.format(path, os.path.splitext(path))) # output #'filename.txt' : ('filename', '.txt') #'filename' : ('filename', '') # '/path/to/filename.txt' : ('/path/to/filename', '.txt') #'/' : ('/', '') #'' : ('', '') #'my-archive.tar.gz' : ('my-archive.tar', '.gz') #'no-extension.' : ('no-extension', '.')
os.extsep
在查詢副檔名時僅匹配最後一次出現的分隔符,因此如果檔名具有多個副檔名,則會按照最後一個副檔名進行拆分。
commonprefix()
將路徑列表作為引數,並返回表示所有路徑中存在的公共字首的單個字串。該值還可以表示實際上不存在的路徑,並且路徑分隔符不包括在考慮中。
import os.path paths = ['/one/two/three/four', '/one/two/threefold', '/one/two/three/', ] for path in paths: print('PATH:', path) print() print('PREFIX:', os.path.commonprefix(paths)) # output # PATH: /one/two/three/four # PATH: /one/two/threefold # PATH: /one/two/three/ # # PREFIX: /one/two/three
在此示例中,公共字首字串是/one/two/three
,即使一個路徑不包含名為的目錄three
。
commonpath()
考慮路徑分隔符,並返回不包含部分路徑值的字首。
import os.path paths = ['/one/two/three/four', '/one/two/threefold', '/one/two/three/', ] for path in paths: print('PATH:', path) print() print('PREFIX:', os.path.commonpath(paths)) # output # PATH: /one/two/three/four # PATH: /one/two/threefold # PATH: /one/two/three/ # # PREFIX: /one/two
構建路徑
除了將現有路徑分開之外,經常需要從其他字串構建路徑。要將多個路徑組合為單個值,可以使用join()
:
import os.path PATHS = [ ('one', 'two', 'three'), ('/', 'one', 'two', 'three'), ('/one', '/two', '/three'), ] for parts in PATHS: print('{} : {!r}'.format(parts, os.path.join(*parts))) # output # ('one', 'two', 'three') : 'one/two/three' # ('/', 'one', 'two', 'three') : '/one/two/three' # ('/one', '/two', '/three') : '/three'
如果有任何一個引數是以os.sep
開頭的,則先前所有的引數都會被丟棄,並將該值作為返回值的開頭。
也可以使用包含可以自動擴充套件的“可變”元件的路徑。例如,expanduser()
將~
字元轉換為使用者主目錄的名稱。
import os.path for user in ['', 'dhellmann', 'nosuchuser']: lookup = '~' + user print('{!r:>15} : {!r}'.format(lookup, os.path.expanduser(lookup))) # output #'~' : '/Users/dhellmann' #'~dhellmann' : '/Users/dhellmann' #'~nosuchuser' : '~nosuchuser'
如果找不到使用者的主目錄,則返回字串不變,如~nosuchuser
。
expandvars()
更通用,擴充套件路徑中存在的任何 shell 環境變數。
import os.path import os os.environ['MYVAR'] = 'VALUE' print(os.path.expandvars('/path/to/$MYVAR'))# /path/to/VALUE
並不會驗證檔案或路徑是否存在。
規範化路徑
使用join()
組合的路徑可能會有額外的分隔符或相對路徑。用normpath()
來清理它們:
import os.path PATHS = [ 'one//two//three', 'one/./two/./three', 'one/../alt/two/three', ] for path in PATHS: print('{!r:>22} : {!r}'.format(path, os.path.normpath(path))) # output #'one//two//three' : 'one/two/three' #'one/./two/./three' : 'one/two/three' # 'one/../alt/two/three' : 'alt/two/three'
要將相對路徑轉換為絕對檔名,請使用abspath()
。
import os import os.path os.chdir('/usr') PATHS = [ '.', '..', './one/two/three', '../one/two/three', ] for path in PATHS: print('{!r:>21} : {!r}'.format(path, os.path.abspath(path))) # output #'.' : '/usr' #'..' : '/' #'./one/two/three' : '/usr/one/two/three' #'../one/two/three' : '/one/two/three'
檔案時間
除了使用路徑之外,os.path
還包括用於檢索檔案屬性的函式,類似於os.stat()
:
import os.path import time print('File:', __file__) print('Access time:', time.ctime(os.path.getatime(__file__))) print('Modified time:', time.ctime(os.path.getmtime(__file__))) print('Change time:', time.ctime(os.path.getctime(__file__))) print('Size:', os.path.getsize(__file__)) # output # File: ospath_properties.py # Access time: Sun Mar 18 16:21:22 2018 # Modified time: Fri Nov 11 17:18:44 2016 # Change time: Fri Nov 11 17:18:44 2016 # Size: 481
os.path.getatime()
返回訪問時間,os.path.getmtime()
返回修改時間,os.path.getctime()
返回建立時間。os.path.getsize()
返回檔案中的資料量,以位元組為單位表示。
測試檔案
當程式遇到路徑名時,通常需要知道路徑是指檔案,目錄還是符號連結以及它是否存在。os.path
包括測試所有這些條件的功能。
import os.path FILENAMES = [ __file__, os.path.dirname(__file__), '/', './broken_link', ] for file in FILENAMES: print('File: {!r}'.format(file)) print('Absolute:', os.path.isabs(file)) print('Is File?:', os.path.isfile(file)) print('Is Dir?:', os.path.isdir(file)) print('Is Link?:', os.path.islink(file)) print('Mountpoint? :', os.path.ismount(file)) print('Exists?:', os.path.exists(file)) print('Link Exists?:', os.path.lexists(file)) print() # output # File: 'ospath_tests.py' # Absolute: False # Is File?: True # Is Dir?: False # Is Link?: False # Mountpoint? : False # Exists?: True # Link Exists?: True # # File: '' # Absolute: False # Is File?: False # Is Dir?: False # Is Link?: False # Mountpoint? : False # Exists?: False # Link Exists?: False # # File: '/' # Absolute: True # Is File?: False # Is Dir?: True # Is Link?: False # Mountpoint? : True # Exists?: True # Link Exists?: True # # File: './broken_link' # Absolute: False # Is File?: False # Is Dir?: False # Is Link?: True # Mountpoint? : False # Exists?: False # Link Exists?: True
所有測試函式都返回布林值。