It is common to see code that calls File.Exists(path) before opening or writing a file. This pattern is problematic and can lead to unexpected bugs. Consider the following code:
C#
if (File.Exists(path))
{
using var stream = File.Open(path, FileMode.Open); // Is it safe?
// ...
}
This code can fail for several reasons. Another application running on the same machine could modify the file between the check and the File.Open call:
- The file can be deleted by another application (including the antivirus)
- The disk can be removed / unmounted
- The network can be disconnected (network drives)
- The application/service that runs Windows Projected File System (ProjFS) stopped
Also, even if the file exists, you may still not be able to open it:
- What about permissions?
- What about readonly / hidden files?
- What if the file is locked (file sharing)?
- What if there is an error on the disk?
File.Exists only tells you whether the file exists at the moment you call it. The returned value is obsolete as soon as the method returns. A result of true does not guarantee the file will still exist when you open it.
Rather than checking whether the file or directory exists before acting, just perform the operation and handle any errors that arise:
C#
try
{
using var stream = File.Open(path, FileMode.Open);
// TODO
}
catch (FileNotFoundException)
{
// TODO
}
catch (DirectoryNotFoundException)
{
// TODO
}
catch (UnauthorizedAccessException)
{
// TODO
}
catch (Exception)
{
// TODO
}
The same applies to Directory operations:
C#
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
// Should be
Directory.CreateDirectory(path);
C#
if (Directory.Exists(path))
{
Directory.Delete(path);
}
// Should be
try
{
Directory.Delete(path);
}
catch(DirectoryNotFoundException)
{
// ok
}
catch(Exception ex)
{
}
#Conclusion
File.Exists/Directory.Exists should only be used when you genuinely want to know whether the file or directory exists at a specific point in time – for example, to skip work when a file is already present. Once the method returns, the information is stale; another process could create or delete the entry at any moment. File.Exists is not a reliable guard before reading or writing a file. Perform the operation directly and handle exceptions. Even when a file exists, you can still encounter errors for many other reasons.
Do you have a question or a suggestion about this post? Contact me!