如何检查System.IO.File.Delete是否成功删除文件

13

使用system.io.file类删除文件后:

System.IO.File.Delete(openedPdfs.path);

如果文件删除成功,我需要运行一些代码。由于该方法不返回任何值,因此在删除方法后,我会检查文件是否存在。如果文件仍然存在,则认为操作失败。

问题是,删除方法运行良好,但是需要几秒钟来删除文件。Exist函数返回true,因为它在检查文件时文件仍然存在。

如何确保System.IO.File.Delete(openedPdfs.path);成功完成?

代码:

FileInfo file = new FileInfo(openedPdfs.path);    
System.IO.File.Delete(openedPdfs.path);
if (file.Exists == false)
{ ... }
else 
{ ... }

1
我认为最优雅的方式是使用 FileSystemWatcher 并订阅其 Deleted 事件。 - Tim Schmelter
3
你是否担心在检查文件存在性之前,已成功删除某个文件,但又创建了一个同名的新文件? - HABO
@TimSchmelter 有人报告说 FileSystemWatcher 在负载下会丢失事件。有人建议可以使用它来提高响应能力,但仍需以降低的间隔轮询以确保不会错过事件。如果过滤器不必要地粗糙,FSW 也可能拖慢性能。 - Andrew Dennison
8个回答

12

正如其他人指出的那样,File.Delete 方法在失败的情况下会抛出异常。

他们遗漏的是,在几乎所有情况下都会抛出异常,但并非所有情况

具体而言,File.Delete 方法不会在要删除的文件不存在时抛出异常。


  • 如果我们查看官方Microsoft System.IO.File.Delete文档,
  • 如果我们跳过抛出的异常列表,
  • 如果我们继续滚动以通过广泛的代码示例来到达“备注”部分,
  • 如果我们尽管它主要由琐碎内容组成仍然继续阅读此部分,例如
    • “使用任何相对或绝对路径指定文件名”
    • “相对路径信息被解释为相对于当前工作目录”
    • “要获取当前工作目录,请参见GetCurrentDirectory”
  • 然后我们会发现以下隐藏在噪音中的小宝石:

如果要删除的文件不存在,则不会抛出任何异常。

换句话说,这个函数故意内置了静默失败

在几乎所有情况下,静默失败都构成了对开发人员的破坏


1
虽然我不是微软的辩护人,但我认为.NET设计避免在大多数情况下调用者不关心文件何时被删除或如何被删除时抛出异常。异常不是报告不太有趣的结果的高效方式。Directory.Create也遵循相同的模式。它通过不报告目录的先前存在来解决竞争条件。在大多数使用情况下,这并不重要。WinAPI通过显式报告整数返回值来处理此问题,而不会抛出昂贵的异常,以准确报告发生了什么或未发生什么。 - Andrew Dennison
无论是“可能的情况”还是“大多数使用情况”,库函数的行为应始终尽可能保持一致。否则,它们将对每个处理不寻常情况的程序员构成破坏。已经足够难以处理不寻常情况了,我们不需要在此基础上再受到库函数的破坏。 - Mike Nakis

1

Delete 如果文件没有被删除,应该抛出异常。因此,您对 Exists 的调用是多余的。

请查看 Delete 文档


3
调用File.Delete完成后,文件实际被删除会有轻微延迟。 - tofutim
16
你的第一句话有误。Delete 不会在文件之前不存在(因此未被删除)时抛出异常。请仔细查看 Delete 的文档:“如果要删除的文件不存在,将不会抛出任何异常。” - mkf

1

这是对Daniel A. White答案的补充:我们可以看到该方法的签名public static void Delete(string path)。因此,你不会从Delete调用中得到反馈,除非出现异常。但假设你有一个文件,另一个进程会定期写入或更新它:

  1. 你的程序成功删除了该文件。
  2. 删除后,其他进程立即重新创建该文件。
  3. 你的程序使用file.Exists测试文件是否存在。有一个同名的新文件,所以返回true。你技术上走了错误的路径。

这种情况可能不适用于你当前尝试解决的问题,但检查Delete调用是否抛出异常比依赖于当前实现要更加健壮。


0
我发现,如果使用FileInfo Delete()实例方法,则不会更新FileInfo实例属性Exists。
例如,以下代码将抛出文件未找到异常,因为文件已被删除,但第二个if (output_file.Exists)仍然计算为true。
FileInfo output_file;
if (output_file.Exists) output_file.Delete();   

FileStream fs;
if (output_file.Exists)
{
     fs = new FileStream(fi.FullName, FileMode.Open, FileAccess.ReadWrite);
}
else
{
     fs = new FileStream(fi.FullName, FileMode.CreateNew, FileAccess.ReadWrite);
}

我发现从旧的FileInfo创建一个新的FileInfo可以解决这个问题:
FileInfo output_file;
if (output_file.Exists)
{
    output_file.Delete();
    output_file = new FileInfo(output_file.FullName);      
}

FileStream fs;
if (output_file.Exists)
{
     fs = new FileStream(fi.FullName, FileMode.Open, FileAccess.ReadWrite);
}
else
{
     fs = new FileStream(fi.FullName, FileMode.CreateNew, FileAccess.ReadWrite);
}

2
你可以使用 output_file.Refresh() 来刷新 FileInfo 的状态。另外,这个回答与问题有什么关系呢? - Lance U. Matthews

0
private String del(String fileLocation) {

 if (File.Exists(@fileLocation)) {
  try {
   File.Delete(@fileLocation);
  } catch (Exception e) {
   return "File couldn't be deleted because: " + e.GetType().Name;
  }
 } else {
  return "File doesn't exist";
 }

 return "File successfully deleted";
}

0

从评论和建议中,您应该能够使用以下内容来实现您想要的结果

try {
  FileInfo file = new FileInfo(openedPdfs.path);    
  System.IO.File.Delete(openedPdfs.path);
  // if no exception is thrown then you should assume all has gone well and put  
  // your file successfully deleted code here.
} catch /*(Specfic exceptions can be referenced here in separate catch blocks see Daniel A. White answer)*/ {
  // If something bad happened and the file was not deleted put handling code here
} finally {
  // if some action needs to be taken regardless of whether the file was successfully deleted or not put 
  // that code here
}

0

如果文件不存在,它不会抛出异常。如果无法删除,则在出现错误的情况下会抛出异常,请检查{{link1:File.Delete}}。


文档中写道:“如果要删除的文件不存在,则不会抛出任何异常。” - Moby Disk
@MobyDisk 是的,但我的意思是它会在出现错误时抛出异常。从技术上讲,删除不存在的文件不算错误。 - Zbigniew

0

你可以随时使用

 System.IO.File.Exists(path)

虽然我同意丹尼尔的看法,但如果Delete不抛出异常,你应该是没问题的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接