昨天,公司的美國客戶發郵件給我,說我的軟體出問題了,我查來查去,發現居然是伺服器上一個目錄無法删除,一删除就報 cannot read from the source file or disk. 如果用指令行方式删除,則報 cannot find the specified path。一開始以為是檔案系統遭破壞了,用 chkdsk 指令檢查,沒有發現問題,後來仔細一看,那個不能删除的目錄名居然以一個空格字元結尾,而我嘗試在資料總管中建立一個目錄以空格結尾結果資料總管會自動将末尾的字元删除,用程式建立,結果也一樣,這個美國佬是怎麼建立這個古怪的目錄的?出現這種情況後不但是無法删除這麼簡單,列目錄什麼的也會有問題,這樣一來,系統的運作都會有問題,我想到的最壞結果就是可能不得不格式化伺服器的硬碟,想到這裡我幾乎不敢再想下去了!Research了一天,後來終于找到了解決方案,并且由此還發現問題的起因是我程式上的一個Bug造成,可怕的Bug!
Windows 的檔案系統可以支援特殊字元的檔案名,比如以空格結尾,以點号結尾等,有一篇英文的文章說NTFS 支援這些檔案名,但FAT不支援,我試了一下,FAT也支援。但Windows API 卻對這些特殊檔案名進行了限制,也就是說,我們通過程式是無法建立一個以空格或點号結尾的檔案名或路徑名的。但Copy 和 Move的API 卻不做這方面的限制,這導緻我們可以從其他的檔案系統拷貝或移動一個特殊檔案名的檔案到Windows 的檔案系統,但一旦在Windows的檔案系統上建立成功,就無法通過正常途徑删除或改名。因為調用API 删除或改名時,API 會首先進行規則檢查,如果發現不符合規則,則直接忽略。這兩組API 在處理上的不一緻,帶來一個非常嚴重的安全問題,可惜微軟到了Windows7 還沒有去彌補這個問題。
下面讓我們用代碼複現這個問題
try
{
string dir = @"C:\Temp\abc";
System.IO.Directory.CreateDirectory(dir); //在C:\Temp 目錄下建立abc 這個目錄
string dir1 = @"c:\Temp\Bcd \";
System.IO.Directory.Move(dir, dir1); //将ABC 移動到"Bcd "這個目錄去,注意這裡 Bcd後面有個空格
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
在運作這段代碼前,你一定要有一點心理準備,因為一旦運作成功,你的 C:\temp 目錄下就有了一個 “Bcd ”這樣的古怪的目錄,而且你用正常的方法根本無法删除它。如果我在此打住,你一定會為之抓狂。不過沒關系,我已經找到了删除它的方法,下面就和大家共享:
Windows 的指令行工具 Del 和 Rd 支援一種方式可以不對輸入檔案名的合法性進行檢查,這種方式是在完整目錄名前加一個
\\?\
比如
del “\\ ?\C:\Temp\xxx. ” 删除xxx. 這個檔案
删除目錄的話
rd /s “ \\?\C:\Temp\xxx. ” 删除 xxx. 這個目錄
執行這個指令後,就可以删除這些古怪的檔案了。注意,這裡一定要輸入完整的目錄才可以,相對路徑不行。
講到這裡,我們知道了原因和解決方案,那麼在這裡我需要提醒大家我們以後在程式中調用 System.IO.Directory.Move 或者 System.IO.File.Copy , System.IO.File.Move 這些函數前,一定要注意先判斷一下輸入的目标檔案名或目錄名的結尾是不是空格或點号,可能還要判斷其他情況,但目前我隻知道這兩種情況,而且結尾是空格非常有隐蔽性。
分類:
作業系統