The Will Will Web

記載著 Will 在網路世界的學習心得與技術分享

建立 NTFS Reparse Points 的方法 ( Soft Link 與 Hard Link )

最近在安裝壹台測試機,由於要架設好幾個站台,每個站台的程式部分大概有 20MB 左右而已,但是搭配著網站進行測試的相關檔案卻有將近 3GB 之多,為了可以順利測試網站這些檔案都必須存在,如果真的複製好幾份的話主機就會頓時浪費許多磁碟空間,這時就可以多加利用建立 檔案連結目錄連結目錄連接 (Junction) 的方式有效減少硬碟空間。

由於 Windows 主機普遍都是採用 NTFS 檔案系統,而在 NTFS 檔案系統裡有關「連結」的種類有好幾款,我第一次接觸時也是霧裡看花,不常用的人真的會搞不清楚這幾種的差別,我先來簡單介紹一下:

在 NTFS 檔案系統裡有種物件類型稱為 NTFS reparse point (不太知道怎樣翻譯這名詞),這是從 NTFS v3.0 也就是 Windows 2000 開始就有的東西,他可以延伸檔案系統對檔案處理的方式,只要在特定目錄或檔案上添加所謂的 Reparse Point Tags 就能讓作業系統或應用程式知道要去哪裡找檔案內容。

簡單來說,NTFS reparse point 可區分成兩大類:

硬式連結 ( Hard Links )

這種連結類型歷史悠久,從 NT 4.0 開始就存在了,他有一個很明顯的限制,就是要建立這種硬式連結實體檔案連結都必須位於同一個磁碟機裡,就算是同一顆硬碟不同分割區也不能跨越。

硬式連結在連接檔案時 (注意: NTFS 不支援目錄硬式連結),所連結的對象並不是「參照檔案的路徑」,而是「參照檔案的 NTFS 檔案位置」,如下圖示代表著你建立完 LINK A.TXTLINK B.TXT 這兩個硬式連結到特定檔案後,他實際上所指向的是磁碟實體的資料位置,並不會記憶建立連結時的檔案路徑與名稱,就算你刪除了原本建立的那個檔案,其資料也不會消失,LINK A.TXTLINK B.TXT 這兩個硬式連結一樣能存取到檔案內容,只有當所有連結到實體磁碟位置的硬式連結都不見了,這個檔案區塊才會正式被宣告為未使用。

以下我們直接舉一個實際的例子來示範其特性,我們先建立一個一般檔案 a.txt 然後再使用 mklink 工具 ( 註: Windows Vista 以上才有此指令 ) 建立硬式連結,建立完之後無論從 DOS 模式下或檔案總管都看不出這兩個檔案有何差異:

有趣的是,當你修改了 a.txt 的內容,其 b.txt 的內容與修改時間會跟 a.txt 完全一模一樣,但兩者的更新時間會差異個幾秒鐘,不過這並不重要,重要的是兩個檔案不管怎樣都會存取到相同檔案內容。

更好玩的是,不管你建立幾份硬式連結磁碟總使用空間都不會變多,但使用檔案總管統計檔案大小時,卻每一份都會給他算進去,因此建立了硬式連結後,磁碟的使用量統計就會有一些失真,這點是必須特別注意的地方。

如果你今天使用的是 Windows Vista 以前的作業系統,例如 Windows Server 2003 或 Windows XP 之類的,要建立硬式連結就必須靠 Fsutil hardlink 命令來建立,如下圖示:

 

軟式連結 ( Soft links )

軟式連結最大的優點就是其連結能夠跨磁碟機建立連結,所以比硬式連結還來的彈性許多,這種連結在 Windows 2000 / XP 以前,只有一種稱為 Junction point 類型,這種類型我在幾年前曾經寫過一篇【介紹好用工具:Junction ( Windows 版的 Soft link ) 】文章,就是用來介紹如何利用 Junction 工具來建立目錄的 Soft Links,其使用時的注意事項也請參考該篇文章的內容。

從 Windows Vista 開始,Windows 開始支援另一種 符號連結 (Symbolic LinkSYMLINK) 的軟式連結,這種連結又比 Junction point 更加來的彈性許多,除了可以建立目錄的 Soft Link 之外,還能建立檔案的 Soft Link,不但能跨越磁碟機,甚至於還能跨伺服器的建立 Soft Link,非常具有彈性!

symbolic link (SYMLINK) 連結來說,在檔案系統中所記錄的是「參照檔案的路徑或檔名」,所以跟硬式連結最大的差異就在於,就算「參照檔案的路徑或檔名」不存在,還是能建立 符號連結。如下圖示,我們試圖建立一個 b.txt 的符號連結,並參考到 a.txt,即便 a.txt 檔案不存在還是能建立符號連結:

這時你從檔案總管可以看出「符號連結」會有不同的圖示,若試圖開啟檔案他會嘗試去解析符號連結所記錄的路徑(相對路徑或絕對路徑皆可),如果找不到檔案就會回報錯誤:

---

瞭解這兩種不同的 NTFS reparse point 之後,最重要的還是要能解決實務上的開發問題,我希望在我們的測試機上不要有太多重複的測試檔案,我們有個目錄下有 8 萬多個檔案,合計將近 3GB,我打算這兩個站台的這些檔案只保留一份就好,另一個站台的目錄就直接用符號連結的方式建立。

比較簡單的作法,我們可以建立「目錄符號連結」最簡單,一個指令就能完成,但在使用 mklink 時要記得加上 /D 參數才行,如下指令與圖示:

mklink /D Temp_Symlink Temp

但我們的另個站台可能會上傳不同的測試資料上去,所以必須用獨立的目錄來儲存這些檔案,因此我們必須大量的建立檔案符號連結才行。

為此我寫了一個好用的批次檔來解決這個問題。以下是批次檔的內容,使用前記得先修改 SourceDir 與 TargetDir 參數,改好之後用滑鼠點兩下即可執行完畢:

@ECHO OFF

:: 請設定來源目錄路徑
SET SourceDir=C:\Inetpub\wwwroot\Content\pictures

:: 請設定要建立【符號連結】的目錄路徑 (所有符號連結的檔案都匯放在這個目錄下)
SET TargetDir=D:\WebTest1\Content\pictures

IF NOT EXIST %SourceDir% (
  ECHO.
  ECHO 查無來源目錄: %SourceDir%
  ECHO.
  GOTO End
)

IF NOT EXIST %TargetDir% (
  ECHO.
  ECHO 查無目標目錄: %TargetDir%
  ECHO.
  GOTO End
)

:: 本批次檔必須放在 TargetDir 目錄執行
CD /D %TargetDir%

:: 取得來源目錄的所有檔案並取得檔案名稱
for /F %%F in ('dir /B %SourceDir%') do (
  :: 若檔案已存在目標路徑則自動跳過建立符號連結
  IF NOT EXIST %%F (
    mklink %%F %SourceDir%\%%F
  )
)

:End

pause

以下是執行時的畫面:

執行完後就會將所有來自於「來源目錄」下的所有檔案全部透過符號連結的方式建立到「目標目錄」下,非常之實用! ^_^

 

相關連結