ZetCode

C# IOException

last modified October 16, 2026

In this article we show how to handle I/O errors in C#.

Working with files, directories, and network connections often causes errors: a file does not exist, a disk is full, or a connection is lost. .NET reports these errors with exceptions. The base class of I/O exceptions is IOException from the System.IO namespace.

The following more specific exceptions derive from IOException:

The exceptions are handled with the try/catch statement. Users of our programs should be presented with easy to understand error messages. More technical details are reserved for administrators; they are often written to log files.

C# unhandled exception

The documentation of each I/O method lists the exceptions that it may throw. For instance, the File.ReadAllText method opens a text file, reads all the text in the file, and then closes the file. It throws a FileNotFoundException if the file does not exist.

Program.cs
var filename = "words.txt";

var content = File.ReadAllText(filename);
Console.WriteLine(content);

The example reads the contents of a text file. There is no exception handling in the program.

$ dotnet run
Unhandled exception. System.IO.FileNotFoundException: Could not find file '/home/user/app/words.txt'.
...

Since the file is missing, the runtime terminates the program and prints the exception with its stack trace.

C# catching IOException

In the next example, we handle the possible error with try/catch.

Program.cs
var filename = "words.txt";

try
{
    var content = File.ReadAllText(filename);
    Console.WriteLine(content);
}
catch (FileNotFoundException e)
{
    Console.WriteLine("Failed to read the file");
    Console.WriteLine($"The file {Path.GetFileName(e.FileName)} does not exist");
}

One of the goals of exception handling is to provide understandable error messages to the users.

Console.WriteLine($"The file {Path.GetFileName(e.FileName)} does not exist");

The FileName property of the exception contains the full path of the missing file.

$ dotnet run
Failed to read the file
The file words.txt does not exist

C# order of catch blocks

A catch block for a base exception also catches the derived exceptions. Therefore, more specific exceptions must be caught first; if a catch (IOException) block preceded a catch (FileNotFoundException) block, the compiler would report the CS0160 error.

Program.cs
string[] paths = ["words.txt", "data/words.txt", "/etc/shadow"];

foreach (var path in paths)
{
    try
    {
        Console.WriteLine(File.ReadAllText(path));
    }
    catch (FileNotFoundException)
    {
        Console.WriteLine($"file not found: {path}");
    }
    catch (DirectoryNotFoundException)
    {
        Console.WriteLine($"directory not found: {path}");
    }
    catch (IOException e)
    {
        Console.WriteLine($"I/O error: {e.Message}");
    }
    catch (UnauthorizedAccessException)
    {
        Console.WriteLine($"access denied: {path}");
    }
}

We try to read three files. The first one does not exist, the second one is in a directory that does not exist, and the third one is a Linux system file that ordinary users cannot read.

catch (UnauthorizedAccessException)

Note that UnauthorizedAccessException does not derive from IOException; the catch (IOException) block does not catch it. It is a common source of unhandled exceptions in file-processing code.

$ dotnet run
file not found: words.txt
directory not found: data/words.txt
access denied: /etc/shadow

C# file in use

A plain IOException is thrown, for instance, when a file is locked by another stream or another process.

Program.cs
var path = "log.txt";

using var first = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None);

try
{
    using var second = new FileStream(path, FileMode.Open, FileAccess.Read);
}
catch (IOException e)
{
    Console.WriteLine(e.GetType().Name);
    Console.WriteLine(e.Message);
}

The first stream opens the file with FileShare.None; no other stream may open the file until the first one is closed.

$ dotnet run
IOException
The process cannot access the file '/home/user/app/log.txt' because it is being used by another process.

C# exception hierarchy

We can check the base class of an exception type with the BaseType property.

Program.cs
Type[] types = [typeof(FileNotFoundException), typeof(EndOfStreamException),
    typeof(PathTooLongException), typeof(UnauthorizedAccessException),
    typeof(OperationCanceledException)];

foreach (var type in types)
{
    Console.WriteLine($"{type.Name,-28} {type.BaseType?.Name}");
}

The first three exceptions derive from IOException. The UnauthorizedAccessException and the OperationCanceledException, which is thrown when an operation is cancelled, derive from SystemException.

$ dotnet run
FileNotFoundException        IOException
EndOfStreamException         IOException
PathTooLongException         IOException
UnauthorizedAccessException  SystemException
OperationCanceledException   SystemException

C# network streams

I/O exceptions are also thrown when we read from and write to network streams. In the following example, we connect to a web server, but we do not send any request. The server does not answer and our read operation times out.

Program.cs
using System.Net.Sockets;
using System.Text;

using var client = new TcpClient();
client.Connect("example.com", 80);

using NetworkStream stream = client.GetStream();
stream.ReadTimeout = 2000;

var buffer = new byte[1024];

try
{
    int n = stream.Read(buffer);
    Console.WriteLine(Encoding.UTF8.GetString(buffer, 0, n));
}
catch (IOException e) when (e.InnerException is SocketException se)
{
    Console.WriteLine("Reading failed");
    Console.WriteLine(e.Message);
    Console.WriteLine(se.SocketErrorCode);
}

The ReadTimeout property sets the time in milliseconds after which a read operation fails.

catch (IOException e) when (e.InnerException is SocketException se)

The network stream wraps the underlying SocketException in an IOException. With an exception filter, we catch only exceptions caused by socket errors and get the error code from the inner exception.

$ dotnet run
Reading failed
Unable to read data from the transport connection: Connection timed out.
TimedOut

Source

Handling I/O errors in .NET

In this article we have worked with I/O exceptions in C#.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all C# tutorials.