"os.path" --- 常見的路徑名操作
******************************

**原始碼：** Lib/genericpath.py、Lib/posixpath.py (用於 POSIX 系統) 和
Lib/ntpath.py (用於 Windows).

======================================================================

該模組實現了一些有用的路徑名操作函式。若要讀取或寫入檔案，請參閱
"open()" 函數，要存取檔案系統，請參閱 "os" 模組。路徑參數可以以字串、
位元組或任何依照 "os.PathLike" 協議實作的物件傳遞。

與 Unix shell 不同，Python 不會*自動*進行路徑展開 (path expansions)。
當應用程式需要進行類似 shell 的路徑展開時，可以明確地呼叫
"expanduser()" 和 "expandvars()" 等函式。（另請參閱 "glob" 模組。）

也參考: "pathlib" 模組提供了高階的路徑物件。

備註:

  所有這些函數都只接受位元組或字串物件作為參數。如果回傳的是路徑或檔案
  名稱，結果將是相同型別的物件。

備註:

  由於不同的作業系統具有不同的路徑命名慣例，在標準函式庫中的路徑模組有
  數個版本可供使用，而 "os.path" 模組都會是運行 Python 之作業系統所適
  用本地路徑。然而，如果你想要操作*始終*以某個不同於本機格式表示的路徑
  ，你也可以引入並使用對應的模組。它們都具有相同的介面：

  * "posixpath" 用於 UNIX 形式的路徑

  * "ntpath" 用於 Windows 的路徑

在 3.8 版的變更: 對於包含有作業系統層級無法表示之字元或位元組的路徑，
"exists()"、"lexists()"、"isdir()"、"isfile()"、"islink()" 和
"ismount()" 函式現在會回傳 "False"，而不是引發例外。

os.path.abspath(path)

   回傳經正規化的絕對路徑名 *path* 。在大多數平台上，這等效於按照以下
   方式呼叫 "normpath()" 函式："normpath(join(os.getcwd(), path))"。

   在 3.6 版的變更: 接受一個 *path-like object*。

os.path.basename(path)

   回傳路徑名 *path* 的基底名稱。這是將 *path* 傳遞給函式 "split()" 後
   回傳結果中的第二個元素。請注意，此函式的結果與 Unix 的 **basename**
   程式不同；對於 "'/foo/bar/'"，**basename** 回傳 "'bar'"，而
   "basename()" 函式回傳空字串（"''"）。

   在 3.6 版的變更: 接受一個 *path-like object*。

os.path.commonpath(paths)

   回傳序列 *paths* 中每個路徑名的最長共同子路徑。如果 *paths* 同時包
   含絕對路徑和相對路徑、*paths* 位於不同的驅動機或 *paths* 為空，則引
   發 "ValueError"。與 "commonprefix()" 不同，此函式回傳的是有效路徑。

   在 3.5 版被加入.

   在 3.6 版的變更: 接受一個*類路徑物件*的序列。

os.path.commonprefix(list)

   回傳 *list* 中所有路徑的最長路徑前綴（逐字元比較）。如果 *list* 為
   空，則回傳空字串（"''"）。

   備註:

     由於此函式是逐字元比較，因此可能會回傳無效的路徑。若要獲得有效的
     路徑，請參考 "commonpath()" 函式。

        >>> os.path.commonprefix(['/usr/lib', '/usr/local/lib'])
        '/usr/l'

        >>> os.path.commonpath(['/usr/lib', '/usr/local/lib'])
        '/usr'

   在 3.6 版的變更: 接受一個 *path-like object*。

os.path.dirname(path)

   回傳路徑名 *path* 的目錄名稱。這是將 *path* 傳遞給函式 "split()" 後
   回傳之成對結果中的第一個元素。

   在 3.6 版的變更: 接受一個 *path-like object*。

os.path.exists(path)

   如果 *path* 是一個存在的路徑或一個開啟的檔案描述器則回傳 "True"。對
   於已損壞的符號連結則回傳 "False"。在某些平台上，即使 *path* 實際存
   在，如果未被授予執行 "os.stat()" 的權限，此函式仍可能回傳 "False"。

   在 3.3 版的變更: 現在 *path* 可以是一個整數：如果它是一個開啟的檔案
   描述器，則回傳 "True"；否則回傳 "False"。

   在 3.6 版的變更: 接受一個 *path-like object*。

os.path.lexists(path)

   如果 *path* 是一個存在的路徑則回傳 "True"，對已損壞的符號連結也是。
   在缺乏 "os.lstat()" 的平台上，與 "exists()" 函式等效。

   在 3.6 版的變更: 接受一個 *path-like object*。

os.path.expanduser(path)

   在 Unix 和 Windows 上，將引數中以 "~" 或 "~user" 開頭的部分替換為該
   *user* 的家目錄。

   在 Unix 上，如果環境變數 "HOME" 有被設置，則將初始的 "~" 替換為該變
   數的值；否則將使用內建模組 "pwd" 在密碼目錄中查找當前使用者的家目錄
   。對於初始的 "~user"，直接在密碼目錄中查找該使用者的家目錄。

   在 Windows 上，如果 "USERPROFILE" 有被設置，則使用該變數的值；否則
   將結合 "HOMEPATH" 和 "HOMEDRIVE"。對於初始的 "~user"，會檢查當前使
   用者的家目錄的最後一個目錄元件是否與 "USERNAME" 相符，如果相符則替
   換它。

   如果展開失敗或路徑不以波浪符號 (tilde) 開頭，則回傳原始路徑，不做任
   何變更。

   在 3.6 版的變更: 接受一個 *path-like object*。

   在 3.8 版的變更: 在 Windows 上不再使用 "HOME" 變數。

os.path.expandvars(path)

   回傳已展開環境變數的引數。形如 "$name" 或 "${name}" 的子字串會被替
   換為環境變數 *name* 的值。無效的變數名稱和對不存在變數的引用保持不
   變。

   在 Windows 上，除了支援 "$name" 和 "${name}" 形式的展開外，還支援
   "%name%" 形式的展開。

   在 3.6 版的變更: 接受一個 *path-like object*。

os.path.getatime(path)

   回傳 *path* 的最後存取時間。回傳值是一個浮點數，表示自紀元（參見
   "time" 模組）以來的秒數。如果檔案不存在或無法存取，則引發 "OSError"
   。

os.path.getmtime(path)

   回傳 *path* 的最後修改時間。回傳值是一個浮點數，表示自紀元（參見
   "time" 模組）以來的秒數。如果檔案不存在或無法存取，則引發 "OSError"
   。

   在 3.6 版的變更: 接受一個 *path-like object*。

os.path.getctime(path)

   回傳系統的 ctime。在某些系統（如 Unix）上，這是最後一次元數據
   (metadata) 更改的時間，在其他系統（如 Windows）上則是 *path* 的建立
   時間。回傳值是一個浮點數，表示自紀元（參見 "time" 模組）以來的秒數
   。如果檔案不存在或無法存取），則引發 "OSError"。

   在 3.6 版的變更: 接受一個 *path-like object*。

os.path.getsize(path)

   回傳 *path* 的大小（以位元組為單位）。如果檔案不存在或無法存取，則
   引發 "OSError"。

   在 3.6 版的變更: 接受一個 *path-like object*。

os.path.isabs(path)

   如果 *path* 是絕對路徑名，則回傳 "True"。在 Unix 上，這表示它以斜線
   開頭；在 Windows 上，表示在去除可能的驅動機字母後，以（反）斜線開頭
   。

   在 3.6 版的變更: 接受一個 *path-like object*。

os.path.isfile(path)

   如果 *path* 是一個"已存在的"常規檔案，則回傳 "True"。這將跟隨符號連
   結，因此同一個路徑可以同時回傳 "islink()" 和 "isfile()" 的結果為真
   。

   在 3.6 版的變更: 接受一個 *path-like object*。

os.path.isdir(path)

   如果 *path* 是一個"已存在的"目錄，則回傳 "True"。這將跟隨符號連結，
   因此同一個路徑可以同時回傳 "islink()" 和 "isfile()" 的結果為真。

   在 3.6 版的變更: 接受一個 *path-like object*。

os.path.isjunction(path)

   如果 *path* 是指向"已存在的"目錄條目且為聯接點 (junction)，則回傳
   "True"。如果目前平台不支援聯接點，則始終返回 "False"。

   在 3.12 版被加入.

os.path.islink(path)

   如果 *path* 是指向"已存在的"目錄項目且為符號連結，則回傳 "True"。如
   果 Python 執行時不支援符號連結，則始終回傳 "False"。

   在 3.6 版的變更: 接受一個 *path-like object*。

os.path.ismount(path)

   如果路徑名 *path* 是一個掛載點 (*mount point*)，則回傳 "True"：即在
   檔案系統中掛載了不同的檔案系統。在 POSIX 系統上，該函式檢查 *path*
   的父目錄 "*path*/.." 是否位於不同的設備上，或者 "*path*/.." 和
   *path* 是否指向同一設備上的相同 i-node --- 這應該能夠檢測出所有
   Unix 和 POSIX 變體的掛載點。但無法可靠地檢測出相同檔案系統上的綁定
   掛載點 (bind mount)。在 Windows 上，以驅動機字母開頭的根目錄和 UNC
   共享路徑始終是掛載點，對於任何其他路徑，會呼叫 "GetVolumePathName"
   函式來檢查它是否與輸入路徑不同。

   在 3.4 版的變更: 新增在 Windows 上檢測非根目錄掛載點的支援。

   在 3.6 版的變更: 接受一個 *path-like object*。

os.path.isdevdrive(path)

   如果路徑名 *path* 位於 Windows Dev 驅動機上，則回傳 "True"。Dev 驅
   動機針對開發人員場景進行了優化，提供更快的讀寫檔案性能。建議將其用
   於原始程式碼、臨時建置目錄、封包快取和其他 I/O 密集型操作。

   可能會對無效的路徑引發錯誤，例如，沒有可識別的驅動機的路徑，但在不
   支援 Dev 磁碟機的平台上返回 "False"。請參閱 Windows 文件以了解有關
   啟用和建立 Dev 驅動機的資訊。

   適用：Windows。

   在 3.12 版被加入.

os.path.join(path, *paths)

   聰明地連接一個或多個路徑段。回傳值是 *path* 和 **paths* 的所有成員
   的串聯，每個非空部分後面都有一個目錄分隔符號，除了最後一個部分。換
   句話說，如果最後一個部分為空或以分隔符號結尾，結果只會以分隔符號結
   尾。如果一個段是絕對路徑（在 Windows 上需要驅動機和根），則忽略所有
   之前的段，並從絕對路徑段繼續連接。

   在 Windows 上，當遇到根路徑段（例如，"r'\foo'"）時，驅動機不會被重
   置。如果一個段位於不同的驅動機上，或者是絕對路徑，則將忽略所有之前
   的段並重置驅動機。請注意，由於每個驅動機都有當前目錄，
   "os.path.join("c:", "foo")" 表示相對於驅動機 "C:" 的當前目錄的路徑
   （即 "c:foo"），而不是 "c:\foo"。

   在 3.6 版的變更: *path* 和 *paths* 接受 *path-like object* 作為參數
   。

os.path.normcase(path)

   將路徑名的大小寫規範化。在 Windows 上，將路徑名中的所有字元轉換為小
   寫，並將正斜線轉換為反斜線。在其他作業系統上，回傳原始路徑。

   在 3.6 版的變更: 接受一個 *path-like object*。

os.path.normpath(path)

   通過合併多餘的分隔符號和上層引用來標準化路徑名，使得 "A//B"、"A/B/"
   、"A/./B" 和 "A/foo/../B" 都變成 "A/B"。這種字串操作可能會改變包含
   符號連結的路徑的含義。在 Windows 上，它將正斜線轉換為反斜線。要標準
   化大小寫，請使用 "normcase()"。

   備註:

     在 POSIX 系統中，根據 IEEE Std 1003.1 2013 版; 4.13 Pathname
     Resolution 標準，如果一個路徑名恰好以兩個斜線開頭，則在前導字元後
     的第一個部分可能會以由實作品自行定義的方式解釋，雖然多於兩個前導
     字元應該被視為單個字元。

   在 3.6 版的變更: 接受一個 *path-like object*。

os.path.realpath(path, *, strict=False)

   回傳指定檔案名稱的規範路徑，消除路徑中遇到的所有符號連結（如果作業
   系統支援）。

   如果路徑不存在或遇到符號連結迴圈，且 *strict* 為 "True"，則引發
   "OSError"。如果 *strict* 為 "False"，則將路徑盡可能解析，並將任何剩
   餘部分附加在後面，而不檢查其是否存在。

   備註:

     此函式模擬作業系統使路徑成為規範的過程，Windows 和 UNIX 之間在鏈
     接和後續路徑部份交互方式方面略有不同。作業系統的 API 會根據需要自
     動使路徑正則，因此通常不需要呼叫此函式。

   在 3.6 版的變更: 接受一個 *path-like object*。

   在 3.8 版的變更: 在 Windows 上，現在會解析符號連結和連接點。

   在 3.10 版的變更: 新增 *strict* 參數。

os.path.relpath(path, start=os.curdir)

   從當前目錄或可選的 *start* 目錄回傳到 *path* 的相對檔案路徑。這是一
   個路徑計算：不會訪問檔案系統來確認 *path* 或 *start* 的存在或屬性。
   在 Windows 上，當 *path* 和 *start* 在不同的驅動機上時，會引發
   "ValueError"。

   *start* 的預設值為 "os.curdir"。

   在 3.6 版的變更: 接受一個 *path-like object*。

os.path.samefile(path1, path2)

   如果兩個路徑名引數指向同一個檔案或目錄，則回傳 "True"。這是通過設備
   編號和 i-node 編號來確定的，如果對任一路徑名的 "os.stat()" 呼叫失敗
   ，則會引發異常。

   在 3.2 版的變更: 新增對 Windows 的支援。

   在 3.4 版的變更: 現在在 Windows 上使用與其他所有平台相同的實作方式
   。

   在 3.6 版的變更: 接受一個 *path-like object*。

os.path.sameopenfile(fp1, fp2)

   如果文件描述符 *fp1* 和 *fp2* 指向同一個檔案，則回傳 "True"。

   在 3.2 版的變更: 新增對 Windows 的支援。

   在 3.6 版的變更: 接受一個 *path-like object*。

os.path.samestat(stat1, stat2)

   如果 stat 值組 *stat1* 和 *stat2* 指向同一個檔案，則回傳 "True"。這
   些結構可能由 "os.fstat()"、"os.lstat()" 或 "os.stat()" 回傳。此函式
   使用 "samefile()" 和 "sameopenfile()" 實現了底層比較。

   在 3.4 版的變更: 新增對 Windows 的支援。

   在 3.6 版的變更: 接受一個 *path-like object*。

os.path.split(path)

   將路徑名 *path* 拆分為 "(head, tail)" 一對，其中 *tail* 是最後一個
   路徑名部份，*head* 是在它之前的所有部分。*tail* 部分不會包含斜線；
   如果 *path* 以斜線結尾，則 *tail* 將為空。如果 *path* 中沒有斜線，
   則 *head* 將為空。如果 *path* 為空，則 *head* 和 *tail* 都為空。除
   非 *head* 是根目錄（僅有一個或多個斜線），否則從 *head* 中刪除尾部
   的斜線。在所有情況下，"join(head, tail)" 回傳指向與 *path* 相同位置
   的路徑（但字串可能不同）。還可以參考函式 "dirname()" 和
   "basename()"。

   在 3.6 版的變更: 接受一個 *path-like object*。

os.path.splitdrive(path)

   將路徑名 *path* 拆分為 "(drive, tail)" 一對，其中 *drive* 是掛載點
   或空字串。在不使用驅動機規範的系統上，*drive* 將始終為空字串。在所
   有情況下，"drive + tail" 將與 *path* 相同。

   在 Windows 上，將路徑名拆分為驅動機或 UNC 共享點以及相對路徑。

   如果路徑包含驅動機字母，則 *drive* 將包含從頭到冒號（包括冒號）的所
   有內容：

      >>> splitdrive("c:/dir")
      ("c:", "/dir")

   如果路徑包含 UNC 路徑，則驅動機將包含主機名和共享名：

      >>> splitdrive("//host/computer/dir")
      ("//host/computer", "/dir")

   在 3.6 版的變更: 接受一個 *path-like object*。

os.path.splitroot(path)

   將路徑名 *path* 拆分為一個 3 項值組 "(drive, root, tail)"，其中
   *drive* 是設備名稱或掛載點，*root* 是驅動機後的分隔符字串，*tail*
   是在根後的所有內容。這些項目中的任何一個都可能是空字串。在所有情況
   下，"drive + root + tail" 將與 *path* 相同。

   在 POSIX 系統上，*drive* 始終為空。*root* 可能為空（如果 *path* 是
   相對路徑），一個斜線（如果 *path* 是絕對路徑），或者兩個斜線（根據
   IEEE Std 1003.1-2017; 4.13 Pathname Resolution 的實作定義）。例如：

      >>> splitroot('/home/sam')
      ('', '/', 'home/sam')
      >>> splitroot('//home/sam')
      ('', '//', 'home/sam')
      >>> splitroot('///home/sam')
      ('', '/', '//home/sam')

   在 Windows 上，*drive* 可能為空、驅動機名稱、UNC 共享或設備名稱。
   *root* 可能為空，斜線或反斜線。例如：

      >>> splitroot('C:/Users/Sam')
      ('C:', '/', 'Users/Sam')
      >>> splitroot('//Server/Share/Users/Sam')
      ('//Server/Share', '/', 'Users/Sam')

   在 3.12 版被加入.

os.path.splitext(path)

   將路徑名 *path* 拆分為一對 "(root, ext)"，使得 "root + ext == path"
   ，且副檔名 *ext* 為空或以點開頭且最多包含一個點 (period)。

   如果路徑不包含副檔名，則 *ext* 將為 "''"：

      >>> splitext('bar')
      ('bar', '')

   如果路徑包含副檔名，則 *ext* 將設置為該副檔名，包括前導的點。請注意
   ，前面的點將被忽略：

      >>> splitext('foo.bar.exe')
      ('foo.bar', '.exe')
      >>> splitext('/foo/bar.exe')
      ('/foo/bar', '.exe')

   路徑的最後一個部份的前導點被認為是根的一部分：

      >>> splitext('.cshrc')
      ('.cshrc', '')
      >>> splitext('/foo/....jpg')
      ('/foo/....jpg', '')

   在 3.6 版的變更: 接受一個 *path-like object*。

os.path.supports_unicode_filenames

   如果可以使用任意的 Unicode 字串作為檔案名（在檔案系統所施加的限制範
   圍內），則回傳 "True"。
