超過一百萬個檔案的 NTFS 資料夾…

在 NTFS 資料夾放入超過一百萬個檔案,會發生什麼事?讀寫檔案會因此變慢嗎?Windows 會不會因此崩潰?

相信很少人有類似經驗,也不會大費周章搞個 Lab 試玩,既然幸運親身體驗過,分享一下經驗。

先說結論:在 NTFS 資料夾放超過一百萬個檔案基本上是可行的(這次遇到的案例超過 150 萬個檔案),若已知完整檔案名稱,讀、寫檔案速度不受檔案數目影響,但會影響檔案總管及部分檔案操作。

我們有個批次轉檔程式會由資料庫讀取資料、存檔後上傳 FTP,每天產生的檔案數約一千筆。因追查問題有時需要檔案內容佐證(跨系統吵架,手握呈堂證供氣勢立刻翻倍呀,你懂的),故需保留檔案。每次調查問題,多半會由資料庫查到檔案名再開 DOS 視窗「notepad 檔名」調閱檔案,用起來很順手方便,感受不到速度延遲,因此大家就忽略了資料夾檔案數每天持續成長,沒人想到要安排定期歸檔搬移排程,就這麼過了七年…

依據 TechNet 文件:NTFS 每個 Volume 的檔案數上限是 4G-1,40 億個檔案放在同一個資料夾理論上是可行的。資料夾使用 B-Tree 結構管理資料,故在已知檔名的前題下,存取檔案的速度不太受同資料夾檔案數多寡影響。資料庫索引也常用 B-Tree 結構儲存索引資料,若已知完整 Key 值,讀取速度不會因為資料筆數倍增明顯下降,也是同樣道理。

關於資料夾可容許的最大檔案數,我沒有找到明確數字。但上述文件提到一個數字(在 Maximum Sizes on an NTFS Volume 段落),如果要在一個資料夾擺放超過 30 萬個檔案,建議停用 8.3 短檔名(尤其是檔名前六碼重複機率很高時),主要是 Windows 會耗費可觀成本避免短檔名重複,推測這只發生在新増或更名時,但是「30 萬」這個數字倒也意味著單一資料夾放幾十萬個檔案仍在 NTFS 設計的容許範圍。

存取檔案速度 OK,問題會出在需要列舉或掃瞄資料夾所有檔案的情境。例如:當資料夾檔案數愈來愈多,就很難再用檔案總管開啟資料夾,一開啟就卡住,甚至導致桌面凍結,只能改用 DOS 視窗,使用 TYPE、COPY 指令存取指定檔名。而且用到 DIR xxxx_*.txt 等篩選條件也會等到地老天荒。這是簡單的數學問題,假設檔案名稱有 32 個字元,100 萬筆檔案清單,光檔名就有 32MB,除了檔名外還有日期時間檔案大小等資料,搜尋時得一一檢查權限,都會消耗記憶體、CPU 並涉及可觀的磁碟 IO 動作。而檔案數一多,系統需串接更多磁區才擺得下目錄資料,列舉檔案清單需由多個零散磁區彙整資料,也會耗費額外的讀取時間。

回到實務案例,雖然已知檔名時讀寫沒什麼感覺,但系統人員發現一些使用上的問題:

  • 檔案總管一打開內有百萬筆檔案的資料夾便卡死沒反應,還無法取消或關閉。到最後,「千萬不要點開 XXX 資料夾(很可怕,不要問)」列為系統管理員口耳相傳的交接事項。
  • DIR 可以執行列出檔案,但只見檔案清單無窮無盡捲個不停,捲到此恨綿綿無絕期,超越常人的耐心極限,檔案總數與大小始終是謎。
  • 單純 DIR 還可以看到檔名狂跑,但 DIR /OD(依日期排序)、DIR *_Blah.txt (篩選檔名特徵)則是一執行就沒反應,直到天荒地老…
  • 想用 .NET Directory.GetFiles() 逐一抓取檔案歸檔,GetFiles() 會一次讀入完整清單,結果…

最後,我寫了支 .NET 歸檔程式,將檔案依日期放在 X:\Archive\yyyy\MM\dd\ 目錄下,而歸檔程式的一項挑戰是不能用 Diretory.GetFiles(),需改用 Directory.EnumerateFiles(),傳回 IEnumerable<string>,每次只取一筆,愚公移山奮戰數小時,將舊檔依日期分類,總算馴服這匹脫韁之馬。

後記,查資料在 Stackoverflow 看到一個資料夾放了 1,400 萬個檔案的案例,結論是 NTFS 資料夾能容納的檔案數比想像多很多,但在這種極端情境下要留意其副作用。

歡迎推文分享:
Published 06 April 2017 06:51 AM 由 Jeffrey
Filed under:
Views: 16,214



意見

# oaww said on 05 April, 2017 08:48 PM

其實我最好奇的是為什麼不留特定區間內的就好XD

# Jeffrey said on 05 April, 2017 08:58 PM

to oaww, 理由挺簡單:一開始是沒想那麼多,後來是發懶沒處理,拖著拖著就… 「糟了,是世界奇觀!」XD

# Ooooops said on 05 April, 2017 09:50 PM

我猜可能是「硬碟比資料庫」便宜太多太多,所以都存在硬碟(資料夾)裡面吧?

# 天空 said on 05 April, 2017 10:00 PM

太有趣啦!

# GregYu said on 05 April, 2017 10:05 PM

開發一隻小程式 (exe) 解決比較完整,

另外,Dos  下的 XCOPY 指令,

有個 /D:m-d-y 的參數,使用說明為:

複製在指定日期當天或之後發生變更的檔案。

如果沒有指定日期,只複製來源檔案時間比目的地時間新的檔案。

理論上也可以透過 [指令檔 (bat、vbs、ps1)] 的方式處理,

只是要從近期的檔案開始往舊的依序處理...

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 
(提醒: 因快取機制,您的留言幾分鐘後才會顯示在網站,請耐心稍候)

5 + 3 =

搜尋

Go

<April 2017>
SunMonTueWedThuFriSat
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456
 
RSS
創用 CC 授權條款
【廣告】
twMVC
最新回應

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


Syndication