在异常处理方面删除文件的最有效方法是什么?

时间:2011-08-12 08:05:33

标签: c# file-io exception-handling

MSDN告诉我们当你调用“File.Delete(path);”时在不存在的文件上生成异常。

在执行删除之前调用delete方法并使用try / catch块来避免错误或验证文件的存在会更有效吗?

我倾向于认为最好避免使用try / catch块。为什么在知道如何检查错误时会发生错误。

无论如何,这里有一些示例代码:

// Option 1: Just delete the file and ignore any exceptions

/// <summary>
/// Remove the files from the local server if the DeleteAfterTransfer flag has been set
/// </summary>
/// <param name="FilesToSend">a list of full file paths to be removed from the local server</param>
private void RemoveLocalFiles(List<string> LocalFiles)
{
    // Ensure there is something to process
    if (LocalFiles != null && LocalFiles.Count > 0 && m_DeleteAfterTransfer == true)
    {
        foreach (string file in LocalFiles)
        {
            try { File.Delete(file); }
            catch { }
        }
    }
}

// Option 2: Check for the existence of the file before delting
private void RemoveLocalFiles(List<string> LocalFiles )
{
    // Ensure there is something to process
    if (LocalFiles != null && LocalFiles.Count > 0 && m_DeleteAfterTransfer == true)
    {
        foreach (string file in LocalFiles)
        {
            if( File.Exists( file ) == true)
                File.Delete(file);
        }
    }
}

我正在努力实现的一些背景: 该代码是FTP包装器类的一部分,它将FTP功能的功能简化为仅需要的功能,并且可以通过单个方法调用来调用。 在这种情况下,我们有一个名为“DeleteAfterTransfer”的标志,如果设置为true将完成该工作。如果文件首先不存在,我希望在达到这一点之前有一个例外。 我想我在这里回答了我自己的问题,但检查文件的存在并不比验证我有权执行任务或任何其他潜在的错误重要。

8 个答案:

答案 0 :(得分:5)

基本上有三个选项,考虑到当你的文件不在时, File.Delete不会抛出异常

  • 使用File.Exists,每次需要额外的往返磁盘(归功于Alexandre C),以及File.Delete到磁盘的往返。这很慢。但是如果你想在文件不存在时做一些特定的事情,这是唯一的方法。

  • 使用异常处理。考虑到entering a try/catch block is relatively fast(我认为大约4-6 m-ops),开销可以忽略不计,您可以选择捕获特定的异常,例如文件正在使用时IOException。这可能非常有用,但是当文件不存在时你将无法行动,因为它不会抛出。 注意:这是避免竞争条件的最简单方法,正如Alexandre C在下面详细解释的那样。

  • 同时使用异常处理 File.Exists。这可能是最慢的,但只是稍微如此,并且当文件不存在时,捕获异常的唯一方法是做某些特定的事情(发出警告?)。


我原始答案的摘要,就使用和处理例外提供了一些更一般的建议:

  • 当控制流程足够时,不要使用异常处理,这样会更有效,更易读。
  • 仅针对例外情况使用例外和例外处理。
  • 输入try / catch的异常处理非常有效,但是当抛出异常时,这个成本相对较高。
  • 上述例外情况是:每当处理文件函数时,都要使用异常处理。原因是竞争条件可能发生,并且您永远不知道if语句和文件删除语句之间发生了什么。
  • 从来没有,我的意思是:从来没有对所有异常使用try / catch(空捕获块,这几乎总是应用程序中的一个弱点,需要改进。只捕获特定的异常。(例外:处理不是从Exception继承的COM异常时)。

答案 1 :(得分:4)

MSDN表示没有生成任何异常。实际上,这种方式更好,因为您遇到竞争条件:在调用File.ExistsFile.Delete之间该文件可能已被其他进程删除或创建。

如果要抛出,则最好捕获可能抛出的特定异常(FileNotFoundException或类似)。请注意,由于竞争条件,例外是唯一的方法。

如果您的问题是包含文件目录不存在,那么您可以这样做:

if (LocalFiles != null && m_DeleteAfterTransfer == true)
{
    foreach (string file in LocalFiles)
    {
        try { File.Delete(file); }
        catch (DirectoryNotFoundException e) {}
    }
}

同样,不要检查之前存在的目录,因为1)它很麻烦2)它具有相同的竞争条件问题。 只有File.Delete才能保证以原子方式执行检查和删除

无论如何,你从不想要捕获每个异常,因为文件IO方法可能由于很多原因而失败(并且你肯定不希望沉默磁盘故障!)

答案 2 :(得分:3)

另一个选择:使用Windows API DeleteFile ...

[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool DeleteFile(string path);

如果完成则返回true,否则返回false。如果为false,则不会有大量的Exceptions开销。

答案 3 :(得分:2)

尝试删除文件时可能会发生许多异常。看看所有这些here。因此,最好在你认为合适的情况下捕捉和处理它们。

答案 4 :(得分:1)

首先做File.Exists要好得多。例外有很大的开销。在效率方面,你的定义不是很清楚,但是性能和内存方面,请File.Exists

另请参阅我之前关于使用Exceptions控制程序流程的问题的答案:

Example of "using exceptions to control flow"

如下所示,我欢迎任何人自己尝试。人们谈论主轴速度和硬盘驱动器的访问时间 - 这是非常不相关的,因为我们没有计时。 OP询问了实现其任务的最佳方式是什么。正如你在这里看到的那样清楚,就是使用File.Exists。这是可重复的。:

实际记录的性能结果:try / catch vs File.Exists表示不存在的文件

文件数量(不存在):10,000

来源http://pastebin.com/6KME40md

<强>结果:

RemoveLocalFiles1 (try / catch):119ms

RemoveLocalFiles2 (File.Exists):106ms

答案 5 :(得分:1)

您应该使用File.Exists,但无论如何都要处理异常。通常,可以在两次调用之间删除文件。处理异常仍然有一些开销,但检查文件是否存在首先会将抛出频率降低到几乎从不。对于上述情况发生的百万分之一的机会,您仍然可能会因未处理的异常而毁掉某人的工作。

答案 6 :(得分:1)

在一般情况下,在调用方法之前测试异常情况确实更好,因为异常不应该用于控制流。

但是,我们在这里处理文件系统,即使您在删除文件之前检查该文件是否存在,否则可能会在您的两次调用之间将其删除。在这种情况下,Delete()即使你明确确定它也不会抛出异常。

所以,在那种特殊情况下,无论如何我都会准备好处理这个例外。

答案 7 :(得分:1)

我认为你不仅要担心效率,还要担心意图。问自己像

这样的问题
  • 文件列表中是否包含不存在的文件是否有错?
  • 您是否担心可能导致无法删除文件的任何其他错误?
  • 如果发生“未找到文件”以外的错误,该过程是否应继续?

显然,即使文件存在,Delete调用也可能失败,因此只添加该检查不会保护您的代码免于失败;你还需要捕捉异常。问题更多的是关于要捕获和处理的异常,以及哪些异常应该向呼叫者传达。