File and Directory I/O Operations in C

File Input/Output (I/O) is an essential aspect of software development that enables applications to persist, read, and manipulate data on the file system. In C#, the System.IO namespace provides two high-level, static classes—File and Directory—that make common operations such as creating, reading, writing, moving, and deleting files and folders straightforward without requiring manual stream management. This guide provides a direct, practical overview of how to use these classes for day-to-day file system tasks.

The System.IO Namespace

To work with these classes, import the System.IO namespace at the top of your C# file:

using System.IO;

Working with the File Class

The static File class provides standard methods for creating, copying, deleting, moving, and opening files, as well as helpers to read and write text or bytes in a single call.

1. Writing to a File

You can write text, an array of strings, or byte arrays to a file. If the file does not exist, these methods create it; if it does exist, they overwrite the content by default.

string filePath = @"C:\temp\example.txt";

// Write a single string to a file
File.WriteAllText(filePath, "Hello, C# File I/O!");

// Write multiple lines from an array or collection
string[] lines = { "First line", "Second line", "Third line" };
File.WriteAllLines(filePath, lines);

// Append text to an existing file without overwriting
File.AppendAllText(filePath, "\nAppended line.");

2. Reading from a File

Reading can be done all at once into a string, an array of lines, or an enumerable collection for memory efficiency.

// Read the entire file as a single string
string content = File.ReadAllText(filePath);

// Read all lines into a string array
string[] readLines = File.ReadAllLines(filePath);

// Lazily enumerate lines to handle large files efficiently
foreach (string line in File.ReadLines(filePath))
{
    Console.WriteLine(line);
}

3. Checking Existence, Copying, Moving, and Deleting

Always check if a file exists before performing destructive operations.

string sourcePath = @"C:\temp\example.txt";
string destinationPath = @"C:\temp\backup.txt";

// Check if file exists
if (File.Exists(sourcePath))
{
    // Copy file (true allows overwriting the destination)
    File.Copy(sourcePath, destinationPath, overwrite: true);

    // Move or rename a file
    string movedPath = @"C:\temp\renamed.txt";
    File.Move(destinationPath, movedPath);

    // Delete a file
    File.Delete(movedPath);
}

Working with the Directory Class

The static Directory class provides functionality for creating, moving, querying, and deleting folders and subfolders.

1. Creating and Deleting Directories

Directory.CreateDirectory creates all directories and subdirectories specified in the path unless they already exist.

string dirPath = @"C:\temp\MyNewFolder";

// Create directory
Directory.CreateDirectory(dirPath);

// Check if directory exists
if (Directory.Exists(dirPath))
{
    // Delete directory (set recursive to true to delete contents as well)
    Directory.Delete(dirPath, recursive: true);
}

2. Listing Files and Subdirectories

You can search within directories using search patterns and control search depth.

string searchDir = @"C:\temp";

// Get all files in a directory
string[] allFiles = Directory.GetFiles(searchDir);

// Get files matching a specific pattern (e.g., text files)
string[] txtFiles = Directory.GetFiles(searchDir, "*.txt");

// Search recursively in all subdirectories
string[] nestedFiles = Directory.GetFiles(searchDir, "*.txt", SearchOption.AllDirectories);

// Get subdirectories
string[] subDirs = Directory.GetDirectories(searchDir);

// Enumerate files lazily for better performance with large directories
foreach (string file in Directory.EnumerateFiles(searchDir, "*.log"))
{
    Console.WriteLine(file);
}

Combining File and Directory with the Path Class

When working with files and folders, avoid hardcoding directory separators. Use the Path class alongside File and Directory to construct reliable file paths:

string folder = @"C:\temp";
string fileName = "report.txt";

// Safely combine paths
string fullPath = Path.Combine(folder, fileName);

// Extract path components
string extension = Path.GetExtension(fullPath);   // returns ".txt"
string baseName = Path.GetFileName(fullPath);     // returns "report.txt"

Exception Handling

File I/O operations involve external resources and are prone to runtime errors such as missing permissions, non-existent paths, or locks by other processes. Wrap operations in try-catch blocks:

try
{
    string data = File.ReadAllText(@"C:\temp\data.txt");
}
catch (FileNotFoundException ex)
{
    Console.WriteLine($"File not found: {ex.Message}");
}
catch (UnauthorizedAccessException ex)
{
    Console.WriteLine($"Access denied: {ex.Message}");
}
catch (IOException ex)
{
    Console.WriteLine($"General I/O error: {ex.Message}");
}