/// <summary>
/// 删除通关步骤文件
/// </summary>
/// <param name="level">关数</param>
private void DeleteStepsFile(int level)
{
File.Delete(GetStepsFileName(fileName, level));
}
/// 删除通关步骤文件
/// </summary>
/// <param name="level">关数</param>
private void DeleteStepsFile(int level)
{
File.Delete(GetStepsFileName(fileName, level));
}
该方法主要用在“编辑”关卡完成后保存数据时删除本关的通关步骤(因为关卡地图都被修改了,原来的通关步骤当然不再适用了)。然而,在一次测试中,发现“编辑”关卡完成后保存数据时居然引发一个“DirectoryNotFoundException”异常。经过查找原因,发现通关步骤文件是保存在“steps”目录下,由于从来没有保存过通关步骤,因此也就没有创建“steps”目录,File.Delete 方法在指定的文件不存在时并不引发异常, 但是如果指定的路径无效,还是会引发 DirectoryNotFoundException 异常。
后来,将 DataFile.DeleteStepsFile 方法改为下面这个样子就正常了(请参见“使用 C# 开发智手机软件:推箱子(十)”):
/// <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);
}
/// 删除通关步骤文件
/// </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.Exists 方法”(该方法不会引发异常):
确定指定的文件是否存在。
命名空间: System.IO
程序集: mscorlib(在 mscorlib.dll 中)
string path
)
请注意,在您调用 Exists 方法和对文件执行其他操作(如 Delete)之间,其他进程可能会对文件进行一些处理。建议的编程做法是在 try...catch 块中包装 Exists 方法和对文件采取的操作,如示例中所示。这有助于缩小潜在冲突的范围。Exists 方法只能帮助确保文件是可用的,但无法保证。
允许 path 参数指定相对或绝对路径信息。相对路径信息被解释为相对于当前工作目录。若要获取当前工作目录,请参见 GetCurrentDirectory。
如果 path 描述一个目录,则此方法返回 false。在确定文件是否存在之前,从 path 参数中移除尾随空格。
现在我们用下面这段程序来测试一下:
using System;
using System.IO;
sealed class Test
{
static void Main(string[] args)
{
try
{
Console.Write("请输入要删除的文件名: ");
string fileName = Console.ReadLine();
if (fileName == "null") fileName = null;
if (args.Length < 1 || File.Exists(fileName))
{
File.Delete(fileName);
Console.WriteLine("File.Delete 成功");
}
}
catch (Exception ex)
{
Console.WriteLine("错误: " + ex.ToString());
}
}
}
using System.IO;
sealed class Test
{
static void Main(string[] args)
{
try
{
Console.Write("请输入要删除的文件名: ");
string fileName = Console.ReadLine();
if (fileName == "null") fileName = null;
if (args.Length < 1 || File.Exists(fileName))
{
File.Delete(fileName);
Console.WriteLine("File.Delete 成功");
}
}
catch (Exception ex)
{
Console.WriteLine("错误: " + ex.ToString());
}
}
}
运行结果如下:
文件名 |
直接调用 File.Delete 方法 D:CSwork>test |
先调用 File.Exists 方法 D:CSwork>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 |
无效的路径 |
请输入要删除的文件名: nonea.txt 错误: System.IO.DirectoryNotFoundException: 未能找到路径“D:CSwork onea.txt”的一部分。 在 System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) 在 System.IO.File.Delete(String path) 在 Test.Main(String[] args) |
请输入要删除的文件名: nonea.txt |
无效的网络路径 |
请输入要删除的文件名: \za.txt 错误: System.IO.IOException: 找不到网络路径。 在 System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) 在 System.IO.File.Delete(String path) 在 Test.Main(String[] args) |
请输入要删除的文件名: \za.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:CSwork est.exe”的访问被拒绝。 在 System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) 在 System.IO.File.Delete(String path) 在 Test.Main(String[] args) |
请输入要删除的文件名: test.exe 错误: System.UnauthorizedAccessException: 对路径“D:CSwork est.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:CSwork eadonly.file”的访问被拒绝。 在 System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath) 在 System.IO.File.Delete(String path) 在 Test.Main(String[] args) |
请输入要删除的文件名: readonly.file 错误: System.UnauthorizedAccessException: 对路径“D:CSwork eadonly.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 方法。