每週一個 Python 模組 | os.path

yongxinz發表於2019-01-28

專欄地址:每週一個 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
複製程式碼

所有測試函式都返回布林值。

相關文件:

pymotw.com/3/os.path/i…

相關文章