File.Exists возвращает истину после File.Delete - PullRequest
0 голосов
/ 11 мая 2018

У меня есть следующий способ удалить файл с указанным путем

private void DestroyFile(string path)
{
    try
    {
        if (File.Exists(path))
        {
            File.Delete(path);
        }
        if (File.Exists(path))
        {
            throw new IOException(string.Format("Failed to delete file: '{0}'.", path));
        }
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

Я получаю IOException, которое выбрасывается, если файл существует после метода File.Delete. В частности

System.IO.IOException): не удалось удалить файл: 'C: \ Windows \ TEMP \ [ИМЯ ФАЙЛА]'.

Я также подтвердил, что файл не существует в месте в переменной пути после завершения выполнения. Мне интересно, не сталкиваюсь ли я с состоянием гонки между обновлением файловой системы после File.Delete и повторной проверкой его с помощью File.Exists. Есть ли лучший способ плавно удалить? Я знаю, что File.Delete не вернет ошибку, если файл не существует, поэтому, возможно, эти проверки немного избыточны. Должен ли я проверить, используется ли файл, а не существует ли он вообще?

Некоторая важная дополнительная информация: Программа может и действительно часто успешно работает, но эта конкретная ошибка часто наблюдалась в последнее время.

Ответы [ 3 ]

0 голосов
/ 11 мая 2018

File.Delete и, как правило, большинство методов из System.IO зависят от файловой системы / потоков / и т. Д., Которые немного живут своей жизнью и не являются управляемыми ресурсами, следовательно, File.Delete может вернуться до физического удаления файла, нопосле того, как он помечен для удаления.

После возврата File.Delete вы можете быть уверены, что файл будет удален, если не этот метод сам вызовет исключение, поэтому вторая проверка с File.Exists и сбросом IOException не нужны.

Если вы хотите пользовательское исключение, ловите исключения из File.Delete.

И в прикрепленном коде помните, что throw ex; отличается от throw; и изменяет трассировку стека на текущую строку.

0 голосов
/ 11 мая 2018

File.Delete будет помечать файл для удаления.Файл действительно будет удален только тогда, когда все дескрипторы к нему закрыты (если таких дескрипторов нет - он всегда будет удален после возврата File.Delete).Как описано для DeleteFile функция winapi (которая используется C # File.Delete):

Функция DeleteFile помечает файл для удаления при закрытии.Поэтому удаление файла не происходит до тех пор, пока последний дескриптор файла не будет закрыт

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

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

Вы можете воспроизвести эту проблему с помощью этой простой программы:

public class Program {
    public static void Main() {
        string path = @"G:\tmp\so\tmp.file";
        // create file with delete share and don't close handle
        var file = new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.Delete);
        DestroyFile(path);
        GC.KeepAlive(file);
    }

    private static void DestroyFile(string path) {
        try {

            if (File.Exists(path)) {
                // no error
                File.Delete(path);
            }
            // but still exists
            if (File.Exists(path)) {
                throw new IOException(string.Format("Failed to delete file: '{0}'.", path));
            }
        }
        catch (Exception ex) {
            throw ex;
        }
    }
}

Вы можете повторить File.Exists проверить навсегда впрограмма выше - файл будет существовать, пока вы не закроете дескриптор.

Так вот, что происходит в вашем случае - какая-то программа имеет открытый дескриптор этого файла с FileShare.Delete.

Вы должны ожидать такогоситуация.Например - просто удалите эту проверку File.Exists, так как вы отметили файл для удаления, и он все равно будет удален.

0 голосов
/ 11 мая 2018

, хотя это не задокументировано в API, File.Delete вернется, пока файл не будет полностью удален.

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

Так что относительно безопасно просто подождать некоторое время.Цикл сразу после того, как ждать, пока файл не исчезнет, ​​или используйте FileSystemWatcher, чтобы посмотреть на удаленное событие

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