tags:

views:

459

answers:

5

Seems to me that File.Exists() is much slower when the file does not exist or the use doesn't have access than when the file does exist? This doesn't make sense to me.

+11  A: 

Generally when you search a bunch of stuff for something, you can't be sure about their lack of existence unless you have searched all possible places it could have been. When searching for something (in most kinds of collections) the worst case is when the item doesn't exist in the collection.

I have not benchmarked File.Exists in particular but I highly doubt that there's a really noticeable difference in those cases unless you're doing it thousands of times. How did you reach to this conclusion?

Mehrdad Afshari
Indeed -- compare to `List<T>.Contains`.
Dan Tao
Consider a file that exists but the user doesn't have access to it. Wouldn't the flow be the same as if the user had? ie: get a pointer to the file and check permissions? Or maybe the permissions prevent finding the file to check permissions on and seems like an empty list? or the same thing you are describing occurs when checking permissions? starting to make a little sense I guess. Thx
Sarah Brown
Yes, permissions are yet another collection to be searched for. If you find what you are looking for, you can give up immediately, whereas to conclude you can't find what you're looking for, you'll have to check off all the possibilities.
Mehrdad Afshari
I reached the conclusion because I had to check File.Exists() on thousands of files from a source list. Over time I noticed the process took longer when more of the files where missing. The difference isn't really noticeable in a smaller context.
Sarah Brown
this doesnt even come close to answering the question.
Brian Leahy
@Sarah what type of path were you using in `File.Exists`? Was it absolute like `C:\Windows\Notepad.exe` or was it like `.\My\File.txt`?
Nick Berardi
Quickest way is to create two lists - one of the files to be found, and one of the file set that you're searching in, sort both lists using quicksort and then compare the lists. It'll be quicker than iterating the file system checking for the existence of files that may not exist. Of course, there is a window of opportunity where the file may be removed from the file system between loading your list and finding the item in it so it's not foolproof but it should speed up your process considerably if this is an acceptable risk.
BenAlabaster
Depending on the input provided, it may have to check all of the entries in the user's path environment variable. Those with older installations might have more in their path, which would slow this down in proportion.
ajs410
+17  A: 

File.Exists is trapping exceptions. The overhead of raising and capturing an exception may contribute to poor performance.

File.Exists works like this: To check to see if the file exists, it tries to open the file... if an exception is thrown the file doesn't exist.

That process is slower than opening a file and no exception is thrown (which is when the file exists).

Bryan Matthews
Thank you. I had noticed that in the documentation and wondered. It probably does impact performance as well. I'd click the up arrow for you but I don't have the reputation yet it seems.
Sarah Brown
That was my first thought, too. @Sarah, if it's really a problem, you may want to fall back to P/Invoking Win32 GetFileAttributes() (which returns -1 if the file is nto found).
peterchen
A: 

File.Exists also instantiates CLR permissioning before checking the file exists for the file. An alternative (though I haven't tried for performance) is PathFileExists if you're doing a lot of checks:

[DllImport("Shlwapi.dll", SetLastError = true, CharSet = CharSet.Auto)]
private extern static bool PathFileExists(StringBuilder path);

void Exists()
{
    StringBuilder builder = new StringBuilder();
    builder.Append(@"C:\test.txt");
    bool exists = PathFileExists(builder);
}
Chris S
A: 

File and all of its methods typically work with windows file handles.

If you do a lot of checks, you should use :

FileInfo fiInfo = new FileInfo(@"c:\donotexists");
if (fiInfo.Exists)
    return true;

Rather than working internally with file handles, it looks at file attributes and is a lot more faster. Besides, it does not check for exceptions, which is a big slow-down in .NET

antesima
It looks like `FileInfo.Exists` ultimately makes the same calls as `File.Exists`. (Using Reflector, you can see that it has to execute `FillAttributeInfo` and open a `SafeFindHandle`, just like `File.Exists`).
Jeff Sternal
+2  A: 

I ran the following test, and on my PC at least, the times are about the same:

  static void TestExists()
     {
     Stopwatch sw = Stopwatch.StartNew();

     for ( int i = 0; i < 1000; i++ )
        {
        if ( !File.Exists( @"c:\tmp\tmp" + i.ToString() + ".tmp" ) )
           Console.WriteLine( "File does not exist" );
        }
     Console.WriteLine( "Total for exists: " + sw.Elapsed );

     sw = Stopwatch.StartNew();
     for ( int i = 0; i < 1000; i++ )
        {
        if ( File.Exists( @"c:\tmp\tmp_" + i.ToString() + ".tmp" ) )
           Console.WriteLine( "File exists" );
        }
     Console.WriteLine( "Total for not exists: " + sw.Elapsed );
     }

The results were along the lines of the following (each run is slightly different but about the same):

Total for exists: 00:00:00.0717181
Total for not exists: 00:00:00.0824266

But across a network (on the LAN to a server one hop away), I found the test to be quite a bit slower when the files actually existed. I sniffed it and there was only one SMB packet each direction.

Total for exists: 00:00:02.4028708
Total for not exists: 00:00:00.6910531
Mark Wilkins