对 File.Delete 方法的一点看法

简介:
在我写的“推箱子”程序的 DataFile 类中有下面这么一个方法:

<!--

Code highlighting produced by Actipro CodeHighlighter (freeware)
http://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)
http://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 参数中移除尾随空格。

    现在我们用下面这段程序来测试一下:

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());
    }

  }

}


    运行结果如下:

文件名 直接调用 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 方法。
相关文章
|
存储 前端开发 机器人
通过4个任务比较LangChain和LlamaIndex
我们在本地使用大模型的时候,尤其是构建RAG应用的时候,一般会有2个成熟的框架可以使用
2730 2
|
数据建模 计算机视觉
SiMBA:基于Mamba的跨图像和多元时间序列的预测模型
微软研究者提出了SiMBA,一种融合Mamba与EinFFT的新架构,用于高效处理图像和时间序列。SiMBA解决了Mamba在大型网络中的不稳定性,结合了卷积、Transformer、频谱方法和状态空间模型的优点。在ImageNet 1K上表现优越,达到84.0%的Top-1准确率,并在多变量长期预测中超越SOTA,降低了MSE和MAE。代码开源,适用于复杂任务的高性能建模。[[论文链接]](https//avoid.overfit.cn/post/c21aa5ca480b47198ee3daefdc7254bb)
1928 3
|
12月前
|
负载均衡 API 数据格式
RPC和HTTP的区别?
RPC和HTTP的区别?
702 0
|
Linux 数据处理 开发者
Linux命令ldd:深入解析动态链接器依赖关系
`ldd`是Linux下分析可执行文件动态依赖的工具,它揭示了程序运行所需的共享库。通过模拟动态链接过程,`ldd`列出库文件路径,帮助理解程序环境和解决运行时问题。主要参数包括`-d`、`-r`、`-u`和`-v`。例如,`ldd my_program`展示`my_program`的依赖关系。注意,`ldd`不显示间接依赖,完整依赖树可能需借助其他工具。确保系统库完整且版本兼容是使用`ldd`时的关键。
|
NoSQL 关系型数据库 MySQL
[AIGC] 对比MySQL全文索引,RedisSearch,和Elasticsearch的详细区别
[AIGC] 对比MySQL全文索引,RedisSearch,和Elasticsearch的详细区别
551 1
|
机器学习/深度学习 人工智能 分布式计算
人工智能平台PAI操作报错合集之遇到报错:PANGU_FILE_NOT_FOUND?如何解决
阿里云人工智能平台PAI (Platform for Artificial Intelligence) 是阿里云推出的一套全面、易用的机器学习和深度学习平台,旨在帮助企业、开发者和数据科学家快速构建、训练、部署和管理人工智能模型。在使用阿里云人工智能平台PAI进行操作时,可能会遇到各种类型的错误。以下列举了一些常见的报错情况及其可能的原因和解决方法。
|
Web App开发 Ubuntu 安全
Linux中的certutil命令:处理证书与证书数据库的实用工具
`certutil`是Linux下的命令行工具,用于处理X.509证书和证书数据库,常与NSS库配合,服务于Firefox等应用。安装`certutil`可通过`apt-get install libnss3-tools`(Debian/Ubuntu)或`yum/dnf install nss-tools`(RHEL/Fedora/CentOS)。基本操作包括:使用`-L`列出证书数据库中的证书,`-A`添加证书,`-D`删除证书,`-x`导出证书。此外,还能用`-M`修改信任设置,`-C`列出证书链,`-V`验证证书链的有效性。了解这些功能有助于高效管理证书。
第18章_MySQL8新特性之CTE(公用表表达式)
第18章_MySQL8新特性之CTE(公用表表达式)
181 0
|
机器学习/深度学习 分布式计算 数据处理
Reactor模型深度解析
Reactor模型深度解析
484 0