Why is File.Exists() much slower when the file does not exist?
Seems to me that File.Exists() is much slower when the file does not exist or the user doesn't have access than when the file does exist.
is this true?
This doesn't make开发者_如何学运维 sense to me.
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).
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()
{
// A StringBuilder is required for interops calls that use strings
StringBuilder builder = new StringBuilder();
builder.Append(@"C:\test.txt");
bool exists = PathFileExists(builder);
}
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?
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
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
精彩评论