對 File.Delete 方法的一點看法
在我寫的“推箱子”程序的 DataFile 類中有下麵這麼一個方法:
<!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
https://www.CodeHighlighter.com/
--> /// <summary>
/// 刪除通關步驟文件
/// </summary>
/// <param name="level">關數</param>
private void DeleteStepsFile(int level)
{
File.Delete(GetStepsFileName(fileName, level));
}
Code highlighting produced by Actipro CodeHighlighter (freeware)
https://www.CodeHighlighter.com/
--> /// <summary>
/// 刪除通關步驟文件
/// </summary>
/// <param name="level">關數</param>
private void DeleteStepsFile(int level)
{
File.Delete(GetStepsFileName(fileName, level));
}
該方法主要用在“編輯”關卡完成後保存數據時刪除本關的通關步驟(因為關卡地圖都被修改了,原來的通關步驟當然不再適用了)。然而,在一次測試中,發現“編輯”關卡完成後保存數據時居然引發一個“DirectoryNotFoundException”異常。經過查找原因,發現通關步驟文件是保存在“steps”目錄下,由於從來沒有保存過通關步驟,因此也就沒有創建“steps”目錄,File.Delete 方法在指定的文件不存在時並不引發異常, 但是如果指定的路徑無效,還是會引發 DirectoryNotFoundException 異常。
後來,將 DataFile.DeleteStepsFile 方法改為下麵這個樣子就正常了(請參見“使用 C# 開發智手機軟件:推箱子(十)”):
<!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
https://www.CodeHighlighter.com/
--> /// <summary>
/// 刪除通關步驟文件
/// </summary>
/// <param name="level">關數</param>
private void DeleteStepsFile(int level)
{
// 雖然 File.Delete(): 刪除指定的文件。如果指定的文件不存在,則不引發異常。
// 但是: 如果指定的路徑無效,還是會引發 DirectoryNotFoundException 異常。
// 所以需要先用 File.Exists() 判斷一下文件是否存在
string name = GetStepsFileName(fileName, level);
if (File.Exists(name)) File.Delete(name);
}
Code highlighting produced by Actipro CodeHighlighter (freeware)
https://www.CodeHighlighter.com/
--> /// <summary>
/// 刪除通關步驟文件
/// </summary>
/// <param name="level">關數</param>
private void DeleteStepsFile(int level)
{
// 雖然 File.Delete(): 刪除指定的文件。如果指定的文件不存在,則不引發異常。
// 但是: 如果指定的路徑無效,還是會引發 DirectoryNotFoundException 異常。
// 所以需要先用 File.Exists() 判斷一下文件是否存在
string name = GetStepsFileName(fileName, level);
if (File.Exists(name)) File.Delete(name);
}
我們來看看 MSDN 上對“File.Delete 方法”的描述:
File.Delete 方法
(System.IO)
刪除指定的文件。如果指定的文件不存在,則不引發異常。
命名空間: System.IO
程序集: mscorlib(在 mscorlib.dll 中)
語法 public static void Delete (
string path
)
參數 path 要刪除的文件的名稱。
異常
異常類型 | 條件 |
ArgumentException | path 是一個零長度字符串,僅包含空白或者包含一個或多個由 InvalidPathChars 定義的無效字符。 |
ArgumentNullException | path 為空引用(在 Visual Basic 中為 Nothing)。 |
DirectoryNotFoundException | 指定的路徑無效(例如,它位於未映射的驅動器上)。 |
IOException | 指定的文件正在使用中。 |
NotSupportedException | path 的格式無效。 |
PathTooLongException | 指定的路徑、文件名或者兩者都超出了係統定義的最大長度。例如,在基於 Windows 的平台上,路徑必須小於 248 個字符,文件名必須小於 260 個字符。 |
UnauthorizedAccessException | 調用方沒有所要求的權限。 - 或 - path 是一個目錄。 - 或 - path 指定一個隻讀文件。 |
備注允許 path 參數指定相對或絕對路徑信息。相對路徑信息被解釋為相對於當前工作目錄。若要獲取當前工作目錄,請參見 GetCurrentDirectory。
有關通用 I/O 任務的列表,請參見 通用 I/O 任務。
Windows NT 4.0 平台說明: Delete 不刪除為正常 I/O 打開的文件或已在內存中映射的文件。
還有“File.Exists 方法”(該方法不會引發異常):
File.Exists 方法
(System.IO)
確定指定的文件是否存在。
命名空間: System.IO
程序集: mscorlib(在 mscorlib.dll 中)
語法 public static bool Exists (
string path
)
參數 path 要檢查的文件。
返回值如果調用方具有要求的權限並且 path 包含現有文件的名稱,則為 true;否則為 false。如果 path 為 空引用(在 Visual Basic 中為 Nothing)、無效路徑或零長度字符串,則此方法也將返回 false。如果調用方不具有讀取指定文件所需的足夠權限,則不引發異常並且該方法返回 false,這與 path 是否存在無關。
備注不應使用 Exists 方法來驗證路徑,此方法僅檢查 path 中指定的文件是否存在。將無效路徑傳遞到 Exists 將返回 false。
請注意,在您調用 Exists 方法和對文件執行其他操作(如 Delete)之間,其他進程可能會對文件進行一些處理。建議的編程做法是在 try...catch 塊中包裝 Exists 方法和對文件采取的操作,如示例中所示。這有助於縮小潛在衝突的範圍。Exists 方法隻能幫助確保文件是可用的,但無法保證。
允許 path 參數指定相對或絕對路徑信息。相對路徑信息被解釋為相對於當前工作目錄。若要獲取當前工作目錄,請參見 GetCurrentDirectory。
如果 path 描述一個目錄,則此方法返回 false。在確定文件是否存在之前,從 path 參數中移除尾隨空格。
現在我們用下麵這段程序來測試一下:



































運行結果如下:
文件名 |
直接調用 File.Delete 方法 D:\CS\work>test |
先調用 File.Exists 方法 D:\CS\work>test with File.Exists |
零長度字符串 | 請輸入要刪除的文件名: 錯誤: System.ArgumentException: 路徑的形式不合法。 在 System.IO.Path.NormalizePathFast(String path, Boolean fullCheck) 在 System.IO.Path.GetFullPathInternal(String path) 在 System.IO.File.Delete(String path) 在 Test.Main(String[] args) |
請輸入要刪除的文件名: |
非法字符 | 請輸入要刪除的文件名: | 錯誤: System.ArgumentException: 路徑中具有非法字符。 在 System.IO.Path.CheckInvalidPathChars(String path) 在 System.IO.Path.NormalizePathFast(String path, Boolean fullCheck) 在 System.IO.Path.GetFullPathInternal(String path) 在 System.IO.File.Delete(String path) 在 Test.Main(String[] args) |
請輸入要刪除的文件名: | |
空引用 | 請輸入要刪除的文件名: null 錯誤: System.ArgumentNullException: 值不能為空。 參數名: path 在 System.IO.File.Delete(String path) 在 Test.Main(String[] args) |
請輸入要刪除的文件名: null |
無效的路徑 | 請輸入要刪除的文件名: none\a.txt 錯誤: System.IO.DirectoryNotFoundException: 未能找到路徑“D:\CS\work\none\a.txt”的一部分。 在 System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) 在 System.IO.File.Delete(String path) 在 Test.Main(String[] args) |
請輸入要刪除的文件名: none\a.txt |
無效的網絡路徑 | 請輸入要刪除的文件名: \\z\a.txt 錯誤: System.IO.IOException: 找不到網絡路徑。 在 System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) 在 System.IO.File.Delete(String path) 在 Test.Main(String[] args) |
請輸入要刪除的文件名: \\z\a.txt |
格式無效 | 請輸入要刪除的文件名: ab: 錯誤: System.NotSupportedException: 不支持給定路徑的格式。 在 System.Security.Util.StringExpressionSet.CanonicalizePath(String path, Boolean needFullPath) 在 System.Security.Util.StringExpressionSet.CreateListFromExpressions(String[] str, Boolean needFullPath) 在 System.Security.Permissions.FileIOPermission.AddPathList(FileIOPermissionAccess access, AccessControlActions control, String[] pathListOrig, Boolean checkForDuplicates, Boolean needFullPath, Boolean copyPathList) 在 System.Security.Permissions.FileIOPermission..ctor(FileIOPermissionAccess access, String[] pathList, Boolean checkForDuplicates, Boolean needFullPath) 在 System.IO.File.Delete(String path) 在 Test.Main(String[] args) |
請輸入要刪除的文件名: ab: |
文件名太長 | 請輸入要刪除的文件名: -this-string's-length-is-249- 錯誤: System.IO.PathTooLongException: 指定的路徑或文件名太長,或者兩者都太長。完全限定文件名必須少於 260 個字符,並且目錄名必須少於 248 個字符。 在 System.IO.Path.NormalizePathFast(String path, Boolean fullCheck) 在 System.IO.Path.GetFullPathInternal(String path) 在 System.IO.File.Delete(String path) 在 Test.Main(String[] args) |
請輸入要刪除的文件名: -this-string's-length-is-249- |
正在使用的文件 | 請輸入要刪除的文件名: test.exe 錯誤: System.UnauthorizedAccessException: 對路徑“D:\CS\work\test.exe”的訪問被拒絕。 在 System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) 在 System.IO.File.Delete(String path) 在 Test.Main(String[] args) |
請輸入要刪除的文件名: test.exe 錯誤: System.UnauthorizedAccessException: 對路徑“D:\CS\work\test.exe”的訪問被拒絕。 在 System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) 在 System.IO.File.Delete(String path) 在 Test.Main(String[] args) |
一個目錄 | 請輸入要刪除的文件名: D:\CS 錯誤: System.UnauthorizedAccessException: 對路徑“D:\CS”的訪問被拒絕。 在 System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) 在 System.IO.File.Delete(String path) 在 Test.Main(String[] args) |
請輸入要刪除的文件名: D:\CS |
隻讀文件 | 請輸入要刪除的文件名: readonly.file 錯誤: System.UnauthorizedAccessException: 對路徑“D:\CS\work\readonly.file”的訪問被拒絕。 在 System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) 在 System.IO.File.Delete(String path) 在 Test.Main(String[] args) |
請輸入要刪除的文件名: readonly.file 錯誤: System.UnauthorizedAccessException: 對路徑“D:\CS\work\readonly.file”的訪問被拒絕。 在 System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) 在 System.IO.File.Delete(String path) 在 Test.Main(String[] args) |
不存在的文件 | 請輸入要刪除的文件名: none.file File.Delete 成功 |
請輸入要刪除的文件名: none.file |
正常的文件 | 請輸入要刪除的文件名: readwrite1.file File.Delete 成功 |
請輸入要刪除的文件名: readwrite2.file File.Delete 成功 |
可以看出,如果先調用 File.Exists 方法判斷一下指定的文件是否存在再決定是否調用 File.Delete 方法,則僅僅在“指定的文件正在使用中”和“指定一個隻讀文件”這兩種情況下會引發異常。而如果直接調用 File.Delete 方法,則在“指定的文件不存在”的情況下不引發異常,但是在“指定的路徑無效”的情況下會引發異常。
實際上,我認為,“指定的路徑無效”應該也算“指定的文件不存在”的一種情況。所以,FCL 中的 File.Delete 方法如果按以下原則進行設計則對開發人員更為友好:
1. File.Delete 方法在“指定的文件不存在”時引發 FileNotFoundException 異常。
2. File.Delete 方法在“指定的文件不存在”和“指定的路徑無效”時不引發異常。
我更傾向於第二種方案。這樣,在大多數情況下,就可以直接調用 File.Delete 方法,而不用先調用 File.Exists 方法。
最後更新:2017-04-02 06:52:19