Каков наиболее эффективный способ удаления файла в отношении обработки исключений? - PullRequest
5 голосов
/ 12 августа 2011

MSDN сообщает нам, что при вызове «File.Delete (path);» для файла, который не существует, генерируется исключение.

Было бы более эффективно вызвать метод удаления и использовать блок 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», и, если установлено значение «истина», мы сделаем эту работу. Если бы файл не существовал в первую очередь, я бы ожидал, что у меня будет исключение, прежде чем я доберусь до этой точки. Я думаю, что отвечаю на свой вопрос здесь, но проверка существования файла менее важна, чем проверка наличия у меня разрешений на выполнение задачи или любых других потенциальных ошибок.

Ответы [ 8 ]

5 голосов
/ 12 августа 2011

По сути, у вас есть три варианта, учитывая, что File.Delete не выдает исключение , когда вашего файла нет:

  • Используйте File.Exists, для которого каждый раз требуется дополнительная передача туда и обратно (кредиты Александру С), а также возврат туда и обратно для File.Delete. Это медленно. Но если вы хотите сделать что-то конкретное, когда файл не существует, это единственный способ.

  • Использовать обработку исключений. Учитывая, что вход в блок try / catch относительно быстрый (примерно 4-6 м-операций, я полагаю), накладные расходы незначительны, и у вас есть возможность перехватить определенные исключения, такие как IOException, когда файл используется. Это может быть очень полезно, но вы не сможете действовать, когда файл не существует, потому что это не выбрасывает. Примечание: это самый простой способ избежать условий гонки, как Александр C объясняет ниже более подробно.

  • Используйте обе обработки исключений и File.Exists. Это потенциально медленнее, но только незначительно, и единственный способ, как ловить исключения и , сделать что-то конкретное (выдать предупреждение?), Когда файл не существует.


Краткое изложение моего первоначального ответа с некоторыми более общими советами по использованию и обработке исключений:

  • Не используйте обработку исключений при достаточном потоке управления, это просто более эффективно и более читабельно.
  • Использовать исключения и обработку исключений только в исключительных случаях.
  • Обработка исключений при вводе try / catch очень эффективна, но когда выдается исключение, это стоит относительно дорого.
  • Исключением из вышеперечисленного является: при работе с файловыми функциями используйте обработку исключений. Причина в том, что могут возникнуть условия гонки, и вы никогда не знаете, что происходит между вашим оператором if и вашим оператором удаления файла.
  • Никогда, и я имею в виду: никогда не используйте try / catch для всех исключений (пустой блок catch, это почти всегда слабое место в вашем приложении и нуждается в улучшении. Улавливайте только определенные исключения. (исключение: при работе с исключениями COM, не наследуемыми от Exception).
4 голосов
/ 12 августа 2011

MSDN говорит, что исключение не генерируется. На самом деле, так будет лучше, поскольку у вас есть условие гонки: между вызовами на File.Exists и File.Delete файл может были удалены или созданы другим процессом.

Если бы он бросил, вам лучше поймать определенное исключение, которое могло быть сгенерировано (FileNotFoundException или подобное). Обратите внимание, что из-за состояния гонки исключения - единственный способ добраться сюда.

Если ваша проблема в том, что директория , содержащая файл , не существует, вы можете сделать:

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

Опять же, не проверяйте существование каталога раньше, потому что 1) он громоздкий 2) у него такая же проблема состояния гонки. Только File.Delete гарантирует, что проверка и удаление выполняются атомарно .

В любом случае, вы никогда не хотите перехватывать здесь все исключения, поскольку методы файлового ввода-вывода могут быть неудачными по многим причинам (а вы , безусловно, не хотите отключать диск при сбое!)

3 голосов
/ 12 августа 2011

Другой вариант: использовать Windows API DeleteFile ...

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

Возвращает true, если выполнено, иначе false.Если false, у вас нет больших накладных расходов на исключения.

2 голосов
/ 12 августа 2011

Существует множество исключений, которые могут возникнуть при попытке удалить файл.Посмотрите здесь для всех из них.Так что, вероятно, лучше всего ловить и разбираться с каждым из них по своему усмотрению.

1 голос
/ 12 августа 2011

Я думаю, вам следует беспокоиться не только об эффективности, но и намерении .Задайте себе такие вопросы, как

  • Является ли ошибочным случай, когда список файлов содержит файлы, которые не существуют?
  • Вас беспокоит какая-либо из других ошибок, которые могут бытьпричина неудачного удаления файла?
  • Должен ли процесс продолжаться, если возникают ошибки, отличные от «файл не найден»?

Очевидно, что вызов Delete может завершиться ошибкой, даже еслифайл существует, поэтому только добавление этой проверки не защитит ваш код от сбоев;Вам все еще нужно поймать исключение.Вопрос больше в , какие исключения нужно отловить и обработать, и какие из них должны быть направлены к вызывающей стороне.

1 голос
/ 12 августа 2011

В общем случае действительно лучше проверить исключительный случай перед вызовом метода, поскольку исключения не должны использоваться для потока управления.

Однако здесь мы имеем дело с файловой системой, и даже если вы проверите, существует ли файл перед его удалением, что-то еще может удалить его между двумя вашими вызовами. В этом случае Delete() все равно выдаст исключение, даже если вы явно убедитесь, что оно не будет.

Итак, в этом конкретном случае я был бы готов обработать исключение в любом случае.

1 голос
/ 12 августа 2011

Вы должны использовать File.Exists, но все равно обработать исключение. В общем случае файл может быть удален между двумя вызовами. Обработка исключения по-прежнему сопряжена с некоторыми накладными расходами, но проверка наличия файла сначала снижает частоту бросков почти до никогда. Если вероятность такого сценария превысит одно, вы все равно можете испортить чью-то работу с необработанным исключением.

1 голос
/ 12 августа 2011

Гораздо лучше сначала сделать File.Exists.Исключения имеют большие накладные расходы.С точки зрения эффективности, ваше определение не очень четкое, но с точки зрения производительности и памяти, выберите File.Exists.

См. Также мой предыдущий ответ на этот вопрос об использовании исключений для управления потоком программ:

Пример «использования исключений для управления потоком»

Как показано ниже, я приглашаю любого попробовать это самостоятельно.Люди, говорящие о скорости вращения шпинделя и времени доступа к жестким дискам, - это совершенно неважно, потому что мы не рассчитываем это.ОП спросил, каков наиболее эффективный способ достижения его задачи.Как вы можете видеть ясно, как день здесь, это использовать File.Exists.Это повторяется .:

Фактические записанные результаты производительности: попытка / отлов против File.Exists для несуществующих файлов

Количество файлов (не существует) : 10 000

Источник : http://pastebin.com/6KME40md

Результаты:

RemoveLocalFiles1 (try / catch): 119ms

RemoveLocalFiles2 (File.Exists): 106ms

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...