Как вы можете легко проверить, запрещен ли доступ к файлу в .NET? - PullRequest
97 голосов
/ 05 ноября 2008

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

Ответы [ 6 ]

150 голосов
/ 05 ноября 2008

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

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

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

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

22 голосов
/ 30 апреля 2009

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

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

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

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

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

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

[Update]

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

/// <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;
}
4 голосов
/ 02 марта 2017

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

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

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

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

3 голосов
/ 05 ноября 2008

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

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

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

0 голосов
/ 06 мая 2019
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;
        }
0 голосов
/ 18 марта 2010
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);
        }
    }
}
...