how can you easily check if access is denied for a file in .NET?
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.
Related videos on Youtube
Horas
Updated on July 08, 2022Comments
-
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 almost 13 yearsAgreed- I wish there were a TryOpen (i.e. Try-Parse pattern).
-
-
Powerlord over 15 yearsExactly. This is a classic example of a race condition.
-
Jason Jackson over 15 yearsIt would be great if there were a "File System Mutex". But without the existence of that, you are dead right.
-
Charu Jain over 15 yearsIsnt 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 over 15 yearskorro: you have to be able to handle bad permissions on failure anyway, and that makes the initial check redundant and wasteful.
-
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 over 14 years@Ash I think u didn read question properly HE wants to avoid try catch.
-
Ravisha over 14 yearsLooks like a good explanation.Althoug i will check once before affirming
-
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 over 14 yearsAn 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 over 14 years-1: use "throw;" not "throw unauthorizedAccessException;". You're losing your stack trace.
-
Konrad Rudolph over 14 yearsWhy is
attempts
passed by ref? That makes no sense. Neither does testing for<=
instead of just==
. -
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 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 over 12 yearsThanks for the code! One thing, it might be better to use using e.g. see Tazeem answer here
-
Cel over 12 yearsGiven you return the filestream then the
using
would have to be used by the caller though ... -
Triynko over 12 yearsThis 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 over 12 yearsIf 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 over 12 yearsIt 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 over 12 yearsFinally, 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 almost 12 yearsGood 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 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 almost 12 yearsRelaying 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 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 over 8 yearsExceptions don't work if you're using some crap closed source library that doesn't throw documented or meaningful exceptions.
-
Joel Coehoorn over 8 years@AndrewWagner But we're not talking about a random library. We're talking mainly about System.IO
-
user2864740 almost 6 yearsFWIW: 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-Exceptional, 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 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 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 over 3 yearsNot working for any of the file on which I have permissions
-
Johanness almost 3 yearsI 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 almost 3 yearsFor 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 almost 3 yearsThis is functionally the same as this answer from 2009 which also uses IOException.