Exception Codes, or Detecting a "File Already Exists" Type Exception
In Trying to Answer This Question, I Was Surprised to Discover That Attempting to Create a New File When That File Already Exists Does Not Throw a Unique...
In trying to answer this question, I was surprised to discover that attempting to create a new file when that file already exists does not throw a unique exception type, it just throws a generic IOException.
I am therefore left wondering how to determine if the IOException is the result of an existing file, or some other IO error.
The exception has an HResult, but this property is protected, and thus unavailable to me.
The only other way I can see is to pattern match the message string which feels awful.
example:
try
{
using (var stream = new FileStream("C:\\Test.txt", FileMode.CreateNew))
using (var writer = new StreamWriter(stream))
{
//write file
}
}
catch (IOException e)
{
//how do I know this is because a file exists?
}
8 Answers
try
{
using (var stream = new FileStream("C:\\Test.txt", FileMode.CreateNew))
using (var writer = new StreamWriter(stream))
{
//write file
}
}
catch (IOException e)
{
var exists = File.Exists(@"C:\Text.text"); // =)
}
Won't work for temp files etc which might have been deleted again.
Here are my exception best practices:
Edit: there is another Hresult that is used when file already exists: 0x800700B7 (-2147024713) "Cannot create a file when that file already exists". Updated the code sample.
When you try to create a new file and it already exists IOException will have Hresult = 0x80070050 (-2147024816).
So you code could look like this:
try
{
using (var stream = new FileStream("C:\\Test.txt", FileMode.CreateNew))
using (var writer = new StreamWriter(stream))
{
//write file
}
}
catch (IOException e)
{
if (e.HResult == -2147024816 ||
e.HResult == -2147024713)
{
// File already exists.
}
}
To modify @jgauffin, in C# 6, you can use the File.Exists inside of the when clause to avoid entering the catch block and thus behaving more like an actual dedicated exception:
try
{
using (var stream = new FileStream("C:\\Test.txt", FileMode.CreateNew))
using (var writer = new StreamWriter(stream))
{
//write file
}
}
catch (IOException e) when (File.Exists(@"C:\Text.text"))
{
//...
}
You can place this condition in your catch statement for IOException: if(ex.Message.Contains("already exists")) { ... }. It is a hack, but it will work for all cases that a file exists, even temporary files and such.
It's not 100% foolproof (there are other reasons for an IOException), but you can at least exclude all derived exception types:
try
{
...
}
catch(IOException e)
{
if (e is UnauthorizedAccessException) throw;
if (e is DirectoryNotFoundException) throw;
if (e is PathTooLongException) throw;
// etc for other exceptions derived from IOException
... assume file exists
}
or the equivalent:
try
{
...
}
catch(UnauthorizedAccessException)
{
throw;
}
catch(DirectoryNotFoundException)
{
throw;
}
catch(PathTooLongException)
{
throw;
}
catch(IOException e)
{
... assume file exists
}
As for the linked question, I'd just check for existence, prompt the user to overwrite, then use OpenOrCreate to overwrite if it exists. I think most apps work this way even if there is a theoretical risk of overwriting a file that's created just at the wrong moment.
In C# 6 and later:
const int WARN_WIN32_FILE_EXISTS = unchecked((int)0x80070050);
try
{
...
}
catch (IOException e) when (e.HResult == WARN_WIN32_FILE_EXISTS)
{
...
}
... or just when (e.HResult == -2147024816), if you're going for "quick and impenetrable". ;-)
(FWIW, the Windows-centric error code has been faithfully copied by Mono and also works on Mac/Linux.)
You can't. Unfortunatly IOExceptions are not further specified for some reason beyond my comprehension in the .NET framework.
But in case of creating a new file it is common practice to check if the file exists first. Like so:
try
{
if (File.Exists("C:\\Test.txt"))
{
//write file
using (var stream = new FileStream("C:\\Test.txt", FileMode.CreateNew))
using (var writer = new StreamWriter(stream))
{
//The actual writing of file
}
}
}
catch (IOException ex)
{
//how do I know this is because a file exists?
Debug.Print(ex.Message);
}
Perhaps not the answer you were looking for. But, c'est ca.
You should use
FileMode.Create
instead of
FileMode.CreateNew
It will override a file if its already exists.