Как вы можете легко проверить, запрещен ли доступ к файлу в.NET?

По сути, я хотел бы проверить, есть ли у меня права на открытие файла, прежде чем я действительно попытаюсь открыть его; Я не хочу использовать попытку / поймать для этой проверки, если я не должен. Есть ли свойство доступа к файлу, которое я могу проверить заранее?

5 ответов

Я делал это бесчисленное количество раз в прошлом, и почти каждый раз, когда я делал это, я ошибался, даже пытаясь сделать это.

Права доступа к файлам (даже существование файлов) изменчивы - они могут измениться в любое время. Благодаря закону Мерфи это особенно касается краткого периода между проверкой файла и попыткой его открыть. Изменение еще более вероятно, если вы находитесь в районе, где вы знаете, что вам нужно проверить в первую очередь. Тем не менее, как ни странно, этого никогда не произойдет в ваших средах тестирования или разработки, которые, как правило, довольно статичны. Это затрудняет обнаружение проблемы позже и облегчает появление такого рода ошибки в производстве.

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

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

Быстрый совет для всех, кто придет сюда с похожей проблемой:

Следите за приложениями веб-синхронизации, такими как DropBox. Я просто потратил 2 часа, думая, что выражение "using" (шаблон Dispose) не работает в.NET.

В конце концов я понял, что Dropbox постоянно читает и пишет файлы в фоновом режиме, чтобы синхронизировать их.

Угадайте, где находится моя папка "Проекты Visual Studio"? Внутри папки "Мой Dropbox", конечно.

Поэтому, когда я запускал свое приложение в режиме отладки, DropBox постоянно обращался к файлам, которые оно читало и записывало для синхронизации с сервером DropBox. Это вызвало конфликты блокировки / доступа.

Так что, по крайней мере, теперь я знаю, что мне нужна более надежная функция открытия файла (например, TryOpen(), которая будет делать несколько попыток). Я удивлен, что это еще не встроенная часть фреймворка.

[Обновить]

Вот моя вспомогательная функция:

/// <summary>
/// Tries to open a file, with a user defined number of attempt and Sleep delay between attempts.
/// </summary>
/// <param name="filePath">The full file path to be opened</param>
/// <param name="fileMode">Required file mode enum value(see MSDN documentation)</param>
/// <param name="fileAccess">Required file access enum value(see MSDN documentation)</param>
/// <param name="fileShare">Required file share enum value(see MSDN documentation)</param>
/// <param name="maximumAttempts">The total number of attempts to make (multiply by attemptWaitMS for the maximum time the function with Try opening the file)</param>
/// <param name="attemptWaitMS">The delay in Milliseconds between each attempt.</param>
/// <returns>A valid FileStream object for the opened file, or null if the File could not be opened after the required attempts</returns>
public FileStream TryOpen(string filePath, FileMode fileMode, FileAccess fileAccess,FileShare fileShare,int maximumAttempts,int attemptWaitMS)
{
    FileStream fs = null;
    int attempts = 0;

    // Loop allow multiple attempts
    while (true)
    {
        try
        {
            fs = File.Open(filePath, fileMode, fileAccess, fileShare);

            //If we get here, the File.Open succeeded, so break out of the loop and return the FileStream
            break;
        }
        catch (IOException ioEx)
        {
            // IOExcception is thrown if the file is in use by another process.

            // Check the numbere of attempts to ensure no infinite loop
            attempts++;
            if (attempts > maximumAttempts)
            {
                // Too many attempts,cannot Open File, break and return null 
                fs = null;
                break;
            }
            else
            {
                // Sleep before making another attempt
                Thread.Sleep(attemptWaitMS);

            }

        }

    }
    // Reutn the filestream, may be valid or null
    return fs;
}

Во-первых, что сказал Джоэл Кохорн.

Кроме того: вы должны изучить предположения, которые лежат в основе вашего желания избегать использования try / catch, если в этом нет необходимости. Типичная причина избегания логики, которая зависит от исключений (создание Exception объекты работают плохо), вероятно, не имеет отношения к коду, открывающему файл.

Я полагаю, что если вы пишете метод, который заполняет List<FileStream> открыв каждый файл в поддереве каталога, и вы ожидаете, что большое количество их будет недоступно, вы можете проверить права доступа к файлу, прежде чем пытаться открыть файл, чтобы вы не получили слишком много исключений. Но вы все равно справитесь с исключением. Кроме того, возможно, что-то ужасно не так с дизайном вашей программы, если вы пишете метод, который делает это.

Вот решение, которое вы ищете

var fileIOPermission = new FileIOPermission(FileIOPermissionAccess.Read,
                                            System.Security.AccessControl.AccessControlActions.View,
                                            MyPath);

if (fileIOPermission.AllFiles == FileIOPermissionAccess.Read)
{
    // Do your thing here...
}

это создает новое разрешение на чтение на основе представления пути ко всем файлам, а затем проверяет, равно ли оно чтению доступа к файлу.

public static bool IsFileLocked(string filename)
        {
            bool Locked = false;
            try
            {
                FileStream fs =
                    File.Open(filename, FileMode.OpenOrCreate,
                    FileAccess.ReadWrite, FileShare.None);
                fs.Close();
            }
            catch (IOException ex)
            {
                Locked = true;
            }
            return Locked;
        }
public static FileStream GetFileStream(String filePath, FileMode fileMode, FileAccess fileAccess, FileShare fileShare, ref int attempts, int attemptWaitInMilliseconds)
{            
    try
    {
         return File.Open(filePath, fileMode, fileAccess, fileShare);
    }
    catch (UnauthorizedAccessException unauthorizedAccessException)
    {
        if (attempts <= 0)
        {
            throw unauthorizedAccessException;
        }
        else
        {
            Thread.Sleep(attemptWaitInMilliseconds);
            attempts--;
            return GetFileStream(filePath, fileMode, fileAccess, fileShare, ref attempts, attemptWaitInMilliseconds);
        }
    }
}
Другие вопросы по тегам