ZetCode

C# DirectoryNotFoundException

last modified April 20, 2025

This tutorial explains how to use the DirectoryNotFoundException class in C# to handle directory-related errors. This exception occurs when a directory cannot be found during file system operations.

The DirectoryNotFoundException class is thrown when part of a directory path is invalid or cannot be found. It inherits from IOException and provides specific information about directory-related failures.

DirectoryNotFoundException helps distinguish directory-specific errors from other I/O exceptions. It's commonly thrown by methods in the Directory, DirectoryInfo, and file-related classes.

Basic DirectoryNotFoundException Example

This example demonstrates catching DirectoryNotFoundException when attempting to access a non-existent directory. We try to get files from a directory that doesn't exist.

Program.cs
using System;
using System.IO;

class Program
{
    static void Main()
    {
        string path = @"C:\NonexistentDirectory";
        
        try
        {
            string[] files = Directory.GetFiles(path);
            Console.WriteLine($"Found {files.Length} files.");
        }
        catch (DirectoryNotFoundException ex)
        {
            Console.WriteLine($"Directory not found: {ex.Message}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Other error: {ex.Message}");
        }
    }
}

The code attempts to get files from a directory that doesn't exist. Directory.GetFiles() throws DirectoryNotFoundException when the specified path is invalid. The exception handler catches this specific error and displays a meaningful message.

The example shows proper exception handling by catching the specific DirectoryNotFoundException before more general exceptions. This allows for targeted error recovery while still catching unexpected errors.

Checking Directory Existence

This example demonstrates the proper way to check if a directory exists before attempting operations, preventing DirectoryNotFoundException.

Program.cs
using System;
using System.IO;

class Program
{
    static void Main()
    {
        string path = @"C:\Temp\Reports";
        
        if (Directory.Exists(path))
        {
            try
            {
                string[] files = Directory.GetFiles(path);
                Console.WriteLine($"Found {files.Length} files in directory.");
            }
            catch (UnauthorizedAccessException ex)
            {
                Console.WriteLine($"Access denied: {ex.Message}");
            }
        }
        else
        {
            Console.WriteLine("Directory does not exist. Creating it...");
            Directory.CreateDirectory(path);
            Console.WriteLine("Directory created successfully.");
        }
    }
}

The code first checks if the directory exists using Directory.Exists. If not, it creates the directory instead of throwing an exception. This is a preventive approach to avoid DirectoryNotFoundException.

The example also shows handling other potential exceptions like UnauthorizedAccessException. This demonstrates defensive programming by checking conditions before operations and handling specific failure cases.

Handling DirectoryNotFoundException in File Operations

This example shows how DirectoryNotFoundException can occur during file operations when the containing directory doesn't exist.

Program.cs
using System;
using System.IO;

class Program
{
    static void Main()
    {
        string filePath = @"C:\NonexistentDirectory\data.txt";
        
        try
        {
            using (StreamWriter writer = new StreamWriter(filePath))
            {
                writer.WriteLine("Test data");
            }
            Console.WriteLine("File written successfully.");
        }
        catch (DirectoryNotFoundException ex)
        {
            Console.WriteLine($"Directory not found: {ex.Message}");
            Console.WriteLine("Creating directory structure...");
            
            Directory.CreateDirectory(Path.GetDirectoryName(filePath));
            Console.WriteLine("Directory created. Try again.");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
    }
}

The code attempts to write to a file in a non-existent directory. The StreamWriter constructor throws DirectoryNotFoundException when the parent directory doesn't exist. The handler catches this and creates the directory.

This example demonstrates both error handling and recovery by automatically creating the missing directory structure. It shows how to extract the directory path from a file path using Path.GetDirectoryName.

DirectoryNotFoundException with DirectoryInfo

This example demonstrates DirectoryNotFoundException when using the DirectoryInfo class to access a non-existent directory.

Program.cs
using System;
using System.IO;

class Program
{
    static void Main()
    {
        string path = @"C:\NonexistentDirectory";
        DirectoryInfo dirInfo = new DirectoryInfo(path);
        
        try
        {
            Console.WriteLine($"Directory attributes: {dirInfo.Attributes}");
            Console.WriteLine($"Last write time: {dirInfo.LastWriteTime}");
        }
        catch (DirectoryNotFoundException ex)
        {
            Console.WriteLine($"Directory not found: {ex.Message}");
            Console.WriteLine($"Attempted path: {ex.Message.Split('\'')[1]}");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error: {ex.Message}");
        }
    }
}

The DirectoryInfo constructor doesn't throw exceptions immediately, but accessing properties like Attributes does when the directory doesn't exist. This behavior differs from static Directory methods.

The example shows how to extract information from the exception message and demonstrates the lazy evaluation nature of DirectoryInfo properties. It's important to understand this difference between Directory and DirectoryInfo.

Recursive Directory Processing with Exception Handling

This example shows how to handle DirectoryNotFoundException when processing directories recursively, which might encounter invalid paths.

Program.cs
using System;
using System.IO;

class Program
{
    static void ProcessDirectory(string path)
    {
        try
        {
            foreach (string dir in Directory.GetDirectories(path))
            {
                ProcessDirectory(dir);
            }
            
            Console.WriteLine($"Processing: {path}");
            // Process files here
        }
        catch (DirectoryNotFoundException ex)
        {
            Console.WriteLine($"Skipping directory: {path} - {ex.Message}");
        }
        catch (UnauthorizedAccessException ex)
        {
            Console.WriteLine($"Access denied: {path} - {ex.Message}");
        }
    }

    static void Main()
    {
        string rootPath = @"C:\SomeDirectory";
        ProcessDirectory(rootPath);
    }
}

The recursive directory processor includes specific handling for DirectoryNotFoundException and other common directory access errors. This allows the processing to continue even if some directories are inaccessible.

This pattern is useful for real-world applications that need to be resilient to partial failures. The example shows how to structure recursive processing with comprehensive error handling.

DirectoryNotFoundException in Multi-threaded Environment

This example demonstrates handling DirectoryNotFoundException in a multi-threaded scenario where directories might be deleted by another thread.

Program.cs
using System;
using System.IO;
using System.Threading;

class Program
{
    static void Worker(object path)
    {
        string dirPath = (string)path;
        
        try
        {
            for (int i = 0; i < 5; i++)
            {
                string[] files = Directory.GetFiles(dirPath);
                Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}: Found {files.Length} files");
                Thread.Sleep(1000);
            }
        }
        catch (DirectoryNotFoundException)
        {
            Console.WriteLine($"{Thread.CurrentThread.ManagedThreadId}: Directory removed during processing");
        }
    }

    static void Main()
    {
        string tempPath = Path.Combine(Path.GetTempPath(), "TempScan");
        Directory.CreateDirectory(tempPath);
        
        // Create some test files
        for (int i = 0; i < 3; i++)
        {
            File.Create(Path.Combine(tempPath, $"file{i}.tmp")).Close();
        }
        
        // Start worker threads
        Thread worker1 = new Thread(Worker);
        Thread worker2 = new Thread(Worker);
        worker1.Start(tempPath);
        worker2.Start(tempPath);
        
        // Simulate directory removal
        Thread.Sleep(2000);
        try
        {
            Directory.Delete(tempPath, true);
            Console.WriteLine("Main thread: Directory deleted");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Main thread: {ex.Message}");
        }
        
        worker1.Join();
        worker2.Join();
    }
}

The example creates a temporary directory and starts multiple threads processing it. The main thread then deletes the directory while workers are still active. Workers handle DirectoryNotFoundException gracefully.

This demonstrates race conditions that can occur in multi-threaded file system operations. The example shows robust error handling for such scenarios, which is common in real-world applications.

Custom DirectoryNotFoundException Handling

This example shows how to create a custom method that wraps directory operations with specific DirectoryNotFoundException handling and recovery.

Program.cs
using System;
using System.IO;

class DirectoryHelper
{
    public static void SafeDirectoryOperation(string path, Action<string> operation)
    {
        int attempts = 0;
        const int maxAttempts = 2;
        
        while (attempts < maxAttempts)
        {
            try
            {
                operation(path);
                return;
            }
            catch (DirectoryNotFoundException)
            {
                attempts++;
                if (attempts >= maxAttempts)
                {
                    Console.WriteLine($"Directory not found after {maxAttempts} attempts");
                    throw;
                }
                
                Console.WriteLine("Directory not found. Attempting to create...");
                Directory.CreateDirectory(path);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error: {ex.Message}");
                throw;
            }
        }
    }
}

class Program
{
    static void Main()
    {
        string path = @"C:\Temp\CustomDirectory\Reports";
        
        try
        {
            DirectoryHelper.SafeDirectoryOperation(path, dirPath =>  
            {
                string[] files = Directory.GetFiles(dirPath);
                Console.WriteLine($"Found {files.Length} files");
            });
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Operation failed: {ex.Message}");
        }
        
        // Test with file creation
        string filePath = Path.Combine(path, "data.txt");
        DirectoryHelper.SafeDirectoryOperation(Path.GetDirectoryName(filePath), dirPath =>  
        {
            using (StreamWriter writer = new StreamWriter(filePath))
            {
                writer.WriteLine("Test data");
            }
            Console.WriteLine("File created successfully");
        });
    }
}

The SafeDirectoryOperation method provides a reusable pattern for handling DirectoryNotFoundException with automatic recovery. It attempts the operation, creates the directory if missing, and retries.

This example demonstrates advanced exception handling patterns, including retry logic and higher-order functions. The custom method can be reused across an application for consistent directory operation handling.

Source

DirectoryNotFoundException Class Documentation

This tutorial covered handling directory-related errors in C# with DirectoryNotFoundException, including prevention, handling, and recovery patterns.

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.