Do more in less time. Block distracting websites with Cold Turkey Pro (Windows, Mac) »

How to handle C# exceptions triggered by inaccessible computer drives?

Situation: Your C# application fetches information from computer drives. However, you aren’t sure that each computer drive is actually available whenever you query it for information. Because an inaccessible drive exception might crash your program, you look for a way to handle those exceptions.

Solution: handle drive exceptions with C#’s try/catch

We retrieve drive information in C# with an instance of the DriveInfo class, which is located in the System.IO namespace. But several properties of that class require that the drive is ready to be queried. Should the drive be unavailable, C# triggers the IOException from the same namespace.

To prevent that exception from crashing our application, we simply wrap querying the DriveInfo properties in a try code block, and then use catch to handle those IOException errors. For instance:

try
{
    // Create an instance of the E:\ drive
    DriveInfo drive = new DriveInfo("E");

    // Query the drive's free space
    Console.WriteLine("Free space in bytes: {0}",
        drive.AvailableFreeSpace);
}
catch (IOException e)
{
    // Handle the exceptions here that
    // are caused by an inaccessible drive

    Console.WriteLine("Error: {0}", e.Message);
}
catch (ArgumentException e)
{
    // Manage exceptions here triggered
    // by an invalid drive letter in 'DriveInfo()'

    Console.WriteLine("Error: {0}", e.Message);
}

If your code repeatedly looks up a specific DriveInfo property, it’s more convenient to wrap the try/catch code in a method like so:

private long DriveFreeSpace(string driveLetter)
{
    try
    {
        return new DriveInfo(driveLetter).AvailableFreeSpace;
    }
    catch
    {
        // Return '-1' to signal that we cannot fetch the drive's
        // free space. This can be caused by an inaccessible drive
        // (gives 'IOException') or a faulty drive letter, in which
        // case 'DriveInfo()' triggers 'ArgumentException'.
        return -1;
    }
}

Discussion: prevent inaccessible drive exceptions in C#

We get drive information in C# with the DriveInfo class from the System.IO namespace (Asad & Ali, 2017; Stephens, 2014). Each instance of that class represents a single computer drive. With that class’ DriveInfo() constructor we can get a single computer drive. Or we use its DriveInfo.GetDrives() method to fetch all the computer’s drives.

DriveInfo properties that need a ready drive

Just over half of DriveInfo properties need the computer drive to be accessible. If the drive is disconnected after we make its DriveInfo instance, our code triggers an exception. (The values for other properties are cached when we make the DriveInfo instance, and so don’t need the drive to be on call.)

DriveInfo properties that need a ready drive and those we can always access are (Microsoft Docs, n.d. a; Stephens, 2014):

Requires a ready driveAccessible at any time
AvailableFreeSpaceDriveType
DriveFormatIsReady
TotalFreeSpaceName
TotalSizeRootDirectory
VolumeLabel

See access a computer drive in C# or query all the computer’s drives for recipes that take a closer look at these properties.

And so we better check if a drive is accessible before we look up a property from the left column. One way to see if a computer drive is ready is with the IsReady property. That property returns true when we can query the drive for information. Should the drive not be ready to be queried, written to, or read from, IsReady returns false (Hilyard & Teilhet, 2015; Microsoft Docs, n.d. b).

Unfortunately, the IsReady property is not 100% reliable because its returned state can quickly change. That is, between the time we check IsReady and query the computer drive its accessibility might have changed (Microsoft Docs, n.d. b). When that happens, we still get the inaccessible drive exception – even though we did check the IsReady property beforehand.

The odds that the user removes the drive in that small time window are tiny. But when our application performs tasks that are relatively time consuming – like retrieve information from a database or download files to store on that disk – the chance that the drive becomes inaccessible does increase.

And so for robust production code, we better implement try/catch code blocks instead of relying on the IsReady property.

Handle possible DriveInfo exceptions with C#’s try/catch

We manage exceptions in C# by putting suspicious code that can trigger an exception in a try/catch code block (Asad & Ali, 2017; Dorman, 2010). Then when the code inside that try code block does trigger an exception, the catch code block that matches the exception type can read the error details and decide what to do next. This way our program doesn’t crash, but deals with errors as they happen.

When we make multiple catch code blocks we can deal with multiple error exceptions that our suspicious code triggers. For that we start with the most specific exception in the first catch code block, and then work our way down to less specific ones (Asad & Ali, 2017; Stephens, 2014). In case of the DriveInfo class, we need to manage IOException exceptions since those signal that a drive is not ready (Microsoft Docs, n.d. b).

In the above recipe solution we implemented the try/catch code block like so:

try
{
    // Create an instance of the E:\ drive
    DriveInfo drive = new DriveInfo("E");

    // Query the drive's free space
    Console.WriteLine("Free space in bytes: {0}",
        drive.AvailableFreeSpace);
}
catch (IOException e)
{
    // Handle the exceptions here that
    // are caused by an inaccessible drive

    Console.WriteLine("Error: {0}", e.Message);
}
catch (ArgumentException e)
{
    // Manage exceptions here triggered
    // by an invalid drive letter in 'DriveInfo()'

    Console.WriteLine("Error: {0}", e.Message);
}

Here the first catch code block handles exceptions triggered by an unready drive. When one of those IOException errors happen, we use the Console.WriteLine() method to print that error’s message. Depending on your program you might want to make a pop-up here that asks the user to select another drive, or simply log the error and then continue without fetching the drive’s available free space.

The other exception we deal with here is an ArgumentException error. An exception of this type happens when we make a DriveInfo instance but provide an incorrect drive letter. And so when the try code that makes an DriveInfo object for the E:\ drive fails, code of this catch code block runs. This way we handle all possible exceptions that the try code can generate. And so whatever happens with that code, our program won’t crash anymore.

Learn more

  • This recipe discussed how we handle exceptions that can happen with computer drives. But in order to access a drive programmatically we need a DriveInfo object. See get drive information in C# and fetch all computer drives for how to do that.
  • As we saw above, some drive properties require a ready computer drive. We can check for a ready drive with the IsReady property. But even then, there’s a small chance that a drive becomes inaccessible between checking IsReady and querying the drive. In that unlikely situation we still get a drive exceptions. To prevent that from happening, we better handle those possible drive exceptions like we discussed above.
  • Drive exceptions not only happen when we query a drive for information. They can also occur when we change a drive’s volume label programmatically. See that recipe for how we’d handle those kinds of exceptions.

References

Asad, A. & Ali, H. (2017). The C# Programmer’s Study Guide (MCSD). New York, NY: Apress.

Dorman, S. (2010). Sams Teach Yourself Visual C# 2010 in 24 Hours. Indianapolis, IN: Sams/Pearson Education.

Hilyard, J. & Teilhet, S. (2015). C# 6.0 Cookbook (4th edition). Sebastopol, CA: O’Reilly Media.

Microsoft Docs (n.d. a). DriveInfo Class. Retrieved on January 29, 2018, from https://docs.microsoft.com/en-us/dotnet/api/system.io.driveinfo?view=netframework-4.7.1

Microsoft Docs (n.d. b). DriveInfo.IsReady Property. Retrieved on January 29, 2018, from https://docs.microsoft.com/nl-nl/dotnet/api/system.io.driveinfo.isready?view=netframework-4.7.1#System_IO_DriveInfo_IsReady

Stephens, R. (2014). C# 5.0 Programmer’s Reference. Indianapolis, IN: John Wiley & Sons.