"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)

   Return the longest common sub-path of each pathname in the iterable
   *paths*.  Raise "ValueError" if *paths* contain both absolute and
   relative pathnames, if *paths* are on different drives, or if
   *paths* is empty.  Unlike "commonprefix()", this returns a valid
   path.

   在 3.5 版被加入.

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

   在 3.13 版的變更: Any iterable can now be passed, rather than just
   sequences.

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)

   Return "True" if *path* is an absolute pathname.  On Unix, that
   means it begins with a slash, on Windows that it begins with two
   (back)slashes, or a drive letter, colon, and (back)slash together.

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

   在 3.13 版的變更: On Windows, returns "False" if the given path
   starts with exactly one (back)slash.

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 驅動機的資訊。

   在 3.12 版被加入.

   在 3.13 版的變更: The function is now available on all platforms,
   and will always return "False" on those that have no support for
   Dev Drives

os.path.isreserved(path)

   Return "True" if *path* is a reserved pathname on the current
   system.

   On Windows, reserved filenames include those that end with a space
   or dot; those that contain colons (i.e. file streams such as
   "name:stream"), wildcard characters (i.e. "'*?"<>'"), pipe, or
   ASCII control characters; as well as DOS device names such as
   "NUL", "CON", "CONIN$", "CONOUT$", "AUX", "PRN", "COM1", and
   "LPT1".

   備註:

     This function approximates rules for reserved paths on most
     Windows systems. These rules change over time in various Windows
     releases. This function may be updated in future Python releases
     as changes to the rules become broadly available.

   適用：Windows。

   在 3.13 版被加入.

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)

   Return the canonical path of the specified filename, eliminating
   any symbolic links encountered in the path (if they are supported
   by the operating system). On Windows, this function will also
   resolve MS-DOS (also called 8.3) style names such as "C:\\PROGRA~1"
   to "C:\\Program Files".

   If a path doesn't exist or a symlink loop is encountered, and
   *strict* is "True", "OSError" is raised. If *strict* is "False"
   these errors are ignored, and so the result might be missing or
   otherwise inaccessible.

   備註:

     此函式模擬作業系統使路徑成為規範的過程，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"。
