在大部分的情況下,我們不會限制使用者輸入檔案路徑的時候一定要使用絕對路徑還是相對路徑。但是在程式處理的過程中,或是需要輸出一些Log資訊的時候,我們可能就必須要將路徑通通都使用絕對路徑來處理了。Rust程式語言標準函式庫中的「fs」模組,以及「Path」和「PathBuf」結構體,雖然有提供「canonicalize」函數或方法,是可以取得檔案的絕對路徑沒錯,但使用起來有一些嚴重的限制。



使用「canonicalize」取得檔案的絕對路徑

如以下程式,可以印出目前工作目錄的上層目錄中的「myfile.txt」檔案的絕對路徑。

請注意,「Path」和「PathBuf」結構體的「canonicalize」方法,實際上是去呼叫「fs」模組的「canonicalize」函數,這個函數會回傳一個「Result」列舉。此時問題來了,在什麼情況下這個「Result」列舉會是「Err」變體呢?當目標檔案不存在的時候就會是「Err」變體(ErrorKind為NotFound)。換句話說,Rust程式語言標準函式庫所提供的取得檔案絕對路徑之功能,目標檔案必須要是存在的狀態才能進行。而且如果該目標檔案是一個捷徑或稱符號鏈接(symbolic link)的話,「canonicalize」函數還會強制地去取得其對應的實體檔案路徑。

那麼要如何單純地去將一個檔案相對路徑解析成絕對路徑,而不去管該路徑的檔案究竟是什麼呢?

Path Absolutize

「Path Absolutize」是筆者開發的套件,可以有效地解析檔案路徑中的點(.)或是點點(..),並根據目前工作目錄,將其轉換成絕對路徑。

Crates.io

https://crates.io/crates/path-absolutize

Cargo.toml

path-absolutize = "*"

使用方法

使用「use」關鍵字來將「path-absolutize」這個crate底下的「Absolutize」特性給引用到當前的程式範圍下,「Path」和「PathBuf」結構體就會擁有「absolutize」和「absolutize_virtually」方法了!這兩個方法都可以將相對路徑轉成絕對路徑。

absolutize

「absolutize」方法的轉換規則如下:

  • 如果路徑不是以點(.)或點點(..)開頭,則點(.)會被忽略,點點(..)表示為上一層節點。
  • 如果路徑是以點(.)或點點(..)開頭,則點(.)表示目前的工作目錄路徑,點點(..)表示目前的工作目錄的上一層目錄。如果目前的工作目錄是根目錄,其上一層目錄也依然還是根目錄。
  • 原路徑如果是一個不是以點(.)或點點(..)開頭的相對路徑,其等同於以點(.)作為路徑開頭。
  • 原路徑如果是有包含點點(..)的絕對路徑,不論原路徑中的點點(..)有多少個,轉換出來的絕對路徑均不會向上超出根目錄。
absolutize_virtually

「absolutize_virtually」方法可以特別限制轉換出來的絕對路徑必須在哪層節點之下。與「absolutize」方法相比有個最大的差異在於,原路徑如果是一個不是以點(.)或點點(..)開頭的相對路徑,並不會預設是在目前的工作目錄下,而是會設在另外傳給「absolutize_virtually」方法的路徑節點之下。這個另外傳進的路徑就像是虛擬的根目錄一樣,不論原路徑中的點點(..)有多少個,轉換出來的虛擬絕對路徑均不會向上超出這個另外傳進的路徑。

Path Absolutize有跨作業系統嗎?

上面貌似都是以Unix-like作業系統(如Linux、macOS)的檔案路徑來舉例,那如果是要用在Windows作業系統呢?別擔心,「Path Absolutize」也是有支援Windows作業系統的,使用方式也完全一樣!例如: