Handling Errors when doing file IO

I came across a pattern in .NET that I’d not thought of before. The scenario is, I’m reading from a file and deserializing it’s contents (a List of ‘Foo’ objects). Exceptions can be thrown at two points:

  • When I’m reading the file
  • When I’m deserialising the xml

Obviously, I want to make sure that the file handle is released if the deserialisation fails. However, I can’t deal with that in a single try block, as if the exception is in the file IO, then the file handle won’t exist to close in a finally block! In other words, this won’t work:

try {
FileStream f = new FileStream(path, FileMode.Open, FileAccess.Read);
_fooList = (List<Foo>) fooSerializer.Deserialize(f);
} catch (Exception e) {
//handle File IO or Serialisation exception
} finally {
f.close(); // This line doesn't work. Outside variable scope.
}

The problem is that if there is an IO exception, f won’t exist to close. Moving the definition of the FileStream to outside the try just causes a compilation error as the f.close() line may be using an uninitialized variable, so you have to check it first, like so:

FileStream f = null;
try {
f = new FileStream(path, FileMode.Open, FileAccess.Read);
_fooList = (List) fooSerializer.Deserialize(f);
} catch (Exception e2) {
//handle File IO exception or Serialisation exception.
} finally {
if (f != null) {
f.close();
}
}

That just seems, well, clunky. I’d prefer to have the variable scoped inside the try, as that’s where it is used, and the checking if f is null is just annoying. Initially, to solve this I came up with:

try {
FileStream f = new FileStream(path, FileMode.Open, FileAccess.Read);
try {
_fooList = (List<Foo>)fooSerializer.Deserialize(f);
} catch (Exception e1){
//handle Serialisation Exception
} finally {
f.close();
}
} catch (Exception e2) {
//handle File IO exception
}

Yuck! I don’t like that you have to handle exceptions in two places, and the complexity of two try..catch blocks, albeit that I liked having f scoped inside a try block. After some thinking, I found a better way:

try {
using (FileStream f = new FileStream(path, FileMode.Open, FileAccess.Read))
{
_fooList = (List<Foo>) fooSerializer.Deserialize(f);
}
}
catch (Exception ex)
{
//handle either File IO or Serialisation exception.
}

This works as the using{} block automatically calls dispose() on the object created in the top line of it (f in this case) when you leave the block, and dispose() and close() are synonymous on FileStreams.

Also, even if the using {} block doesn’t tidy up the FileStream when you leave because of an exception (and I’m pretty sure it does), you are now outside the variable scope of f, so the garbage collector will clear it up – which includes calling f‘s finalizer (or destructor, for C++ bods) which in turn calls dispose() if required.

Thus, your file will not be stuck open.

Anyway, the short of it – the above pattern is a good way of opening a file and doing stuff with it, while handling errors in one catch block, and making sure that exceptions don’t leave the file locked open.

Advertisement
Handling Errors when doing file IO

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.