how can you easily check if access is denied for a file in .NET?

100,772

Solution 1

I have done this countless times in the past, and nearly every time I was wrong to even make the attempt.

File permissions (even file existence) are volatile — they can change at any time. Thanks to Murphy's Law this especially includes the brief period between when you check the file and when you try to open it. There are other reasons this can fail, too, such as locking or network availability and path resolution. An errant result is even more likely if you're in an area where you know you need to check first. Yet strangely enough it will never happen in your testing or development environments, which tend to be fairly static. This makes the problem difficult to track down later and makes it easy for this kind of bug to make it into production.

What this means is you must still be ready to handle the exception if file permissions or existence are bad, in spite of your check. Exception handling code is required, whether or not you check the file in advance, and good exception handler can provide all of the functionality of existence or permissions checks.

But isn't exception handling slow? I'm glad you asked. Yes, yes it is. In fact, unwinding the stack to handle an exception is up there with the slowest stuff you can do inside a single computer. However, it's important to remember that disk I/O is even slower — a lot slower — and calling the .Exists() function or checking permissions will always force an additional I/O operation on the file system.

Therefore, we see an initial check before trying to open the file is both redundant and wasteful. There is no additional benefit over exception handling. It will actually hurt, not help, your performance. It adds cost in terms of more code that must be maintained. Finally, it can introduce subtle bugs. There is just no upside at all to doing the initial check.

Instead, the correct thing here is immediately trying to open the file, with no initial check, and putting your effort into a good exception handler if it fails. The same is true whether you're checking permissions, locking, or even just whether or not the file exists.

In summary: the choice is paying the extra cost for file check every time with more code, or paying the smaller-but-still-bad cost for exception handling only some of the time and with less code.

Solution 2

Quick tip for anyone else coming here with a similar problem:

Watch out for web synchronization apps such as DropBox. I just spent 2 hours thinking the "using" statement (Dispose pattern) is broken in .NET.

I eventually realised that Dropbox is continually reading and writing files in the background, in order to sync them.

Guess where my Visual Studio Projects folder is located? Inside the "My Dropbox" folder of course.

Therefore as I ran my application in Debug mode, the files it was reading and writing were also continually being accessed by DropBox to be synched with the DropBox server. This caused the locking/access conflicts.

So at least I now know that I need to a more robust File Open function (ie TryOpen() that will make multiple attempts). I am surprised it's not already a built-in part of the framework.

[Update]

Here's my helper function:

/// <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;
}

Solution 3

First, what Joel Coehoorn said.

Also: you should examine the assumptions that underly your desire to avoid using try/catch unless you have to. The typical reason for avoiding logic that depends on exceptions (creating Exception objects performs poorly) probably isn't relevant to code that's opening a file.

I suppose that if you're writing a method that populates a List<FileStream> by opening every file in a directory subtree and you expected large numbers of them to be inaccessible you might want to check file permissions before trying to open a file so that you didn't get too many exceptions. But you'd still handle the exception. Also, there's probably something terribly wrong with your program's design if you're writing a method that does this.

Solution 4

Here is the solution you are looking for

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

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

this creates a new permission of read based on view for path of all files then checks if it's equal to file access read.

Share:
100,772

Related videos on Youtube

Horas
Author by

Horas

Updated on July 08, 2022

Comments

  • Horas
    Horas almost 2 years

    Basically, I would like to check if I have rights to open the file before I actually try to open it; I do not want to use a try/catch for this check unless I have to. Is there a file access property I can check before hand?

    • Tristan
      Tristan almost 13 years
      Agreed- I wish there were a TryOpen (i.e. Try-Parse pattern).
  • Powerlord
    Powerlord over 15 years
    Exactly. This is a classic example of a race condition.
  • Jason Jackson
    Jason Jackson over 15 years
    It would be great if there were a "File System Mutex". But without the existence of that, you are dead right.
  • Charu Jain
    Charu Jain over 15 years
    Isnt the question about file opening rights/permissions? So first you check if you have permission on this file, and then only if you have permission, you try if it's available?
  • Joel Coehoorn
    Joel Coehoorn over 15 years
    korro: you have to be able to handle bad permissions on failure anyway, and that makes the initial check redundant and wasteful.
  • Joel Coehoorn
    Joel Coehoorn over 15 years
    @chrissie: linux has the same issue. It's a file system thing, and ext2/3/reiser/etc are not immune.
  • Ravisha
    Ravisha over 14 years
    @Ash I think u didn read question properly HE wants to avoid try catch.
  • Ravisha
    Ravisha over 14 years
    Looks like a good explanation.Althoug i will check once before affirming
  • Ash
    Ash over 14 years
    @Ravisha, did you even read Joel's top voted answer? As Joel says, "What you do instead is just try to open the file and handle the exception if it fails". Please don't downvote just because you don't like the fact that something cannot be avoided.
  • peterchen
    peterchen over 14 years
    An initial check can help to handle common specific errors gracefully - looking ahead is often easier than matching particular exception attributes to specific causes. The try/catch still remains obligatory.
  • John Saunders
    John Saunders over 14 years
    -1: use "throw;" not "throw unauthorizedAccessException;". You're losing your stack trace.
  • Konrad Rudolph
    Konrad Rudolph over 14 years
    Why is attempts passed by ref? That makes no sense. Neither does testing for <= instead of just ==.
  • Konrad Rudolph
    Konrad Rudolph over 14 years
    @John: well, in this case it’s desirable to lose the (deeply nested) stack trace of the recursive call so I think in this instance throw ex is actually the right thing to do.
  • John Saunders
    John Saunders over 14 years
    @Konrad: @Rudzitis: I'm changing my reason for the -1. It's worse than screwing the stack by "throw ex". You're screwing the stack by artificially inducing extra stack levels through recursion at a time when stack depth actually matters. This is an iterative problem, not a recursive one.
  • Cel
    Cel over 12 years
    Thanks for the code! One thing, it might be better to use using e.g. see Tazeem answer here
  • Cel
    Cel over 12 years
    Given you return the filestream then the using would have to be used by the caller though ...
  • Triynko
    Triynko over 12 years
    This answer does not answer the question "how to check whether I have rights to open the file" at some instance before trying to open it. The case may very well be, that if permission is not allowed at that instance, the software will not attempt to read the file, even if permission may very well be granted just after permissions were checked.
  • Triynko
    Triynko over 12 years
    If you're strictly trying to open a file... then sure, committing to open a file handle with permissions as they are at that instance, as an atomic file system operation, is the only way to reliably determine whether you had access. On the other hand, there should be a way to test whether your user account SHOULD have read access to a file at the time you're checking for access.
  • Triynko
    Triynko over 12 years
    It doesn't matter whether permissions are volatile, when you only care what they are at that instant. Failure should always be handled, but if you check for a read permission and it's not there, then you may want to skip reading the file, even if it's possible that a second later you might have access. You have to draw the line somewhere.
  • Triynko
    Triynko over 12 years
    Finally, obtaining effective permissions from the ACL is demonstrated here in a few lines of purely managed code: stackoverflow.com/a/1281638/88409 It's not that hard.
  • Kit10
    Kit10 almost 12 years
    Good info, however, I definitely disagree that an extra check is wasteful. That's like saying any check of an expected failure is wasteful, instead let it fail and recover. In C# (as with many other languages that support exceptions), there is a popular paradigm that exceptions are reserved for unrecoverable failures. Often exception code is exceptionally slower than pre-exception tests.
  • Joel Coehoorn
    Joel Coehoorn almost 12 years
    @Copperpot It is true that exception handling code is often significantly slower. However, what we save here is an extra trip out to disk. Trips to disk are orders of magnitude slower even than extra exception handling. If you don't like seeing the try/catch in your control flow, well, you could try to hide it away in a method, but part of my point is that you still have to write that code somewhere, because the .Exists() call isn't reliable enough to do without it.
  • habakuk
    habakuk almost 12 years
    Relaying on exceptions for a false condition is very costly (Stacktrace needs much time to be generated). You are much faster if you can discard a file operation when you check weather you can access it or not, before.
  • Joel Coehoorn
    Joel Coehoorn almost 12 years
    @habakuk that would be nice if you were actually checking before you accessed the file, but that's not the way it works. Calling File.Exists() does require a trip out to disk. As slow as exceptions are, the file io is still way worse.
  • Andrew Wagner
    Andrew Wagner over 8 years
    Exceptions don't work if you're using some crap closed source library that doesn't throw documented or meaningful exceptions.
  • Joel Coehoorn
    Joel Coehoorn over 8 years
    @AndrewWagner But we're not talking about a random library. We're talking mainly about System.IO
  • user2864740
    user2864740 almost 6 years
    FWIW: Stack-trace captures are relatively cheap - it's the later access to them is what is "most expensive". Where "expensive" is some inconsequential time - ie. still measured in usecs - in any reasonable usage this is .. not interesting to fret over. See mattwarren.org/2016/12/20/Why-Exceptions-should-be-Exception‌​al, eg. So much time worried about a few usec is probably not super productive - one can easily write an own 'TryOpen' and have it not dominate program time..
  • ToolmakerSteve
    ToolmakerSteve about 5 years
    @Cel - using won't work here. At the end of the using block, fs will be forced closed. You will give the caller a CLOSED (so useless) filestream!
  • ToolmakerSteve
    ToolmakerSteve about 5 years
    @JoelCoehoorn - I'm surprised by your comment that calling File.Exists first requires an extra trip out to disk. No, File.Exists, followed shortly by an attempt to open, will only require a single read of directory info into cache. AFAIK, its not a significant loss of time vs reading w/o the exists check. I personally do File.Exists first (sometimes), because it handles certain conditions (e.g. bad file path) without throwing an exception.
  • Manish Dubey
    Manish Dubey over 3 years
    Not working for any of the file on which I have permissions
  • Johanness
    Johanness almost 3 years
    I am just now writing an application that needs access to several directories on different servers at different times. In this scenario it totally makes sense to check at startup if all permissions are ok. I will still have to cope with volatile connections, but testing a whole cycle just to realize your user doesn't have the right permission for the final task is not fun.
  • Tedd Hansen
    Tedd Hansen almost 3 years
    For anyone coming here for a quick copy-paste solution, this might be it. FileIOPermission solution in other answer is deprecated in .Net Core. Do read the answer about race condition though. For my current use case this works perfectly. I just need to wait for/detect new file, then detect when write lock is released so I can start processing it. No race condition issue.
  • Wai Ha Lee
    Wai Ha Lee almost 3 years
    This is functionally the same as this answer from 2009 which also uses IOException.