Skip to main content

C# File Operations

Introduction

File operations are a fundamental part of many applications. Whether you're building a text editor, a data processing tool, or a system utility, you'll often need to interact with files on the filesystem. C# provides robust and easy-to-use classes for various file operations through the System.IO namespace.

In this tutorial, we'll explore common file operations including:

  • Checking if files exist
  • Creating files
  • Reading from files
  • Writing to files
  • Copying and moving files
  • Deleting files
  • Getting file information

These operations form the building blocks for more complex file handling tasks in your applications.

Prerequisites

Before we dive in, make sure you have:

  • Basic knowledge of C# syntax
  • A development environment (Visual Studio, VS Code, etc.) with .NET installed
  • Understanding of basic programming concepts

Let's start by adding the required namespace to our code:

csharp
using System;
using System.IO;

Checking if a File Exists

Before performing operations on a file, it's often necessary to check if the file exists:

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

if (File.Exists(filePath))
{
Console.WriteLine($"The file {filePath} exists.");
}
else
{
Console.WriteLine($"The file {filePath} does not exist.");
}

Output (if file doesn't exist):

The file C:\example\sample.txt does not exist.

Creating Files

C# offers multiple ways to create files. Here are two common approaches:

1. Using File.Create()

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

try
{
// Create a file - returns a FileStream
using (FileStream fs = File.Create(filePath))
{
// File created successfully
Console.WriteLine($"File created at {filePath}");
}
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred: {ex.Message}");
}

2. Using StreamWriter

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

try
{
// Create a file and write some initial content
using (StreamWriter writer = new StreamWriter(filePath))
{
writer.WriteLine("This is the first line.");
Console.WriteLine($"File created at {filePath} with initial content");
}
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred: {ex.Message}");
}

Reading from Files

There are several ways to read from files in C#:

1. Reading All Text at Once

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

try
{
// Read all content at once
string content = File.ReadAllText(filePath);
Console.WriteLine("File content:");
Console.WriteLine(content);
}
catch (FileNotFoundException)
{
Console.WriteLine($"The file {filePath} was not found.");
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred: {ex.Message}");
}

2. Reading Line by Line

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

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

Console.WriteLine("File content line by line:");
for (int i = 0; i < lines.Length; i++)
{
Console.WriteLine($"Line {i+1}: {lines[i]}");
}
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred: {ex.Message}");
}

3. Reading with StreamReader

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

try
{
using (StreamReader reader = new StreamReader(filePath))
{
string line;
int lineNumber = 1;

Console.WriteLine("File content (using StreamReader):");
// Read line by line until the end of the file
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine($"Line {lineNumber++}: {line}");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred: {ex.Message}");
}

Writing to Files

Similar to reading, C# provides multiple ways to write content to files:

1. Writing All Text at Once

csharp
string filePath = @"C:\example\output.txt";
string content = "Hello, world!\nThis is a sample text.\nWritten using C#.";

try
{
// Write all text at once (overwrites existing content)
File.WriteAllText(filePath, content);
Console.WriteLine($"Content written to {filePath}");
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred: {ex.Message}");
}

2. Writing Line by Line

csharp
string filePath = @"C:\example\lines.txt";
string[] lines = {
"First line",
"Second line",
"Third line",
"Fourth line"
};

try
{
// Write all lines at once
File.WriteAllLines(filePath, lines);
Console.WriteLine($"Lines written to {filePath}");
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred: {ex.Message}");
}

3. Appending to Files

csharp
string filePath = @"C:\example\log.txt";
string newEntry = $"[{DateTime.Now}] Application started";

try
{
// Append text to existing file
File.AppendAllText(filePath, newEntry + Environment.NewLine);
Console.WriteLine($"Entry appended to {filePath}");
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred: {ex.Message}");
}

4. Using StreamWriter

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

try
{
// true parameter enables appending
using (StreamWriter writer = new StreamWriter(filePath, true))
{
writer.WriteLine("This is a line written using StreamWriter");
writer.WriteLine($"Current timestamp: {DateTime.Now}");
writer.WriteLine(new string('-', 30)); // Separator line
}
Console.WriteLine($"Content written to {filePath}");
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred: {ex.Message}");
}

Copying and Moving Files

Copying Files

csharp
string sourceFile = @"C:\example\source.txt";
string destinationFile = @"C:\example\backup\source-copy.txt";

try
{
// Create directory if it doesn't exist
Directory.CreateDirectory(Path.GetDirectoryName(destinationFile));

// Copy file (set overwrite to true)
File.Copy(sourceFile, destinationFile, true);
Console.WriteLine($"File copied from {sourceFile} to {destinationFile}");
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred: {ex.Message}");
}

Moving Files

csharp
string sourceFile = @"C:\example\source.txt";
string destinationFile = @"C:\example\moved\source.txt";

try
{
// Create directory if it doesn't exist
Directory.CreateDirectory(Path.GetDirectoryName(destinationFile));

// Move file
File.Move(sourceFile, destinationFile);
Console.WriteLine($"File moved from {sourceFile} to {destinationFile}");
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred: {ex.Message}");
}

Deleting Files

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

try
{
// Check if file exists before attempting to delete
if (File.Exists(filePath))
{
File.Delete(filePath);
Console.WriteLine($"File {filePath} deleted successfully");
}
else
{
Console.WriteLine($"File {filePath} does not exist");
}
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred: {ex.Message}");
}

Getting File Information

The FileInfo class provides useful methods and properties for working with files:

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

try
{
FileInfo fileInfo = new FileInfo(filePath);

if (fileInfo.Exists)
{
Console.WriteLine($"File name: {fileInfo.Name}");
Console.WriteLine($"Full path: {fileInfo.FullName}");
Console.WriteLine($"Directory: {fileInfo.DirectoryName}");
Console.WriteLine($"Size: {fileInfo.Length} bytes");
Console.WriteLine($"Extension: {fileInfo.Extension}");
Console.WriteLine($"Creation time: {fileInfo.CreationTime}");
Console.WriteLine($"Last access time: {fileInfo.LastAccessTime}");
Console.WriteLine($"Last write time: {fileInfo.LastWriteTime}");
Console.WriteLine($"Attributes: {fileInfo.Attributes}");
}
else
{
Console.WriteLine($"The file {filePath} does not exist.");
}
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred: {ex.Message}");
}

Practical Example: Simple Log File System

Let's create a practical example of a simple logging system that:

  1. Creates a log file if it doesn't exist
  2. Appends log entries with timestamps
  3. Can display the most recent logs
csharp
public class SimpleLogger
{
private readonly string _logFilePath;

public SimpleLogger(string logFilePath)
{
_logFilePath = logFilePath;

// Create directory if it doesn't exist
string directory = Path.GetDirectoryName(_logFilePath);
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
}

public void Log(string message, string level = "INFO")
{
string logEntry = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] [{level}] {message}";

try
{
// Append the log entry
File.AppendAllText(_logFilePath, logEntry + Environment.NewLine);
}
catch (Exception ex)
{
Console.WriteLine($"Failed to write to log file: {ex.Message}");
}
}

public void DisplayLastNLogs(int n)
{
try
{
if (!File.Exists(_logFilePath))
{
Console.WriteLine("Log file does not exist yet.");
return;
}

// Read all lines and get the last N entries
string[] allLogs = File.ReadAllLines(_logFilePath);

int startIndex = Math.Max(0, allLogs.Length - n);
Console.WriteLine($"Last {Math.Min(n, allLogs.Length)} log entries:");

for (int i = startIndex; i < allLogs.Length; i++)
{
Console.WriteLine(allLogs[i]);
}
}
catch (Exception ex)
{
Console.WriteLine($"Error reading logs: {ex.Message}");
}
}
}

// Example usage
public void LoggingExample()
{
SimpleLogger logger = new SimpleLogger(@"C:\logs\application.log");

// Log some messages
logger.Log("Application started");
logger.Log("User logged in: JohnDoe", "USER");
logger.Log("Database connection established", "DB");
logger.Log("Invalid password attempt for user: guest", "WARNING");
logger.Log("System exception occurred: Out of memory", "ERROR");

// Display last 3 logs
logger.DisplayLastNLogs(3);
}

Output:

Last 3 log entries:
[2023-09-25 14:32:45] [DB] Database connection established
[2023-09-25 14:32:45] [WARNING] Invalid password attempt for user: guest
[2023-09-25 14:32:45] [ERROR] System exception occurred: Out of memory

Practical Example: File Backup Utility

Here's another real-world example - a simple file backup utility:

csharp
public class FileBackup
{
public void BackupFile(string sourcePath, string backupDirectory, bool appendTimestamp = true)
{
try
{
// Ensure source file exists
if (!File.Exists(sourcePath))
{
Console.WriteLine($"Source file not found: {sourcePath}");
return;
}

// Create backup directory if it doesn't exist
if (!Directory.Exists(backupDirectory))
{
Directory.CreateDirectory(backupDirectory);
Console.WriteLine($"Created backup directory: {backupDirectory}");
}

// Get file name from path
string fileName = Path.GetFileName(sourcePath);
string destinationPath;

if (appendTimestamp)
{
// Add timestamp to filename
string fileNameWithoutExt = Path.GetFileNameWithoutExtension(fileName);
string extension = Path.GetExtension(fileName);
string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");

destinationPath = Path.Combine(
backupDirectory,
$"{fileNameWithoutExt}_{timestamp}{extension}"
);
}
else
{
destinationPath = Path.Combine(backupDirectory, fileName);
}

// Copy the file
File.Copy(sourcePath, destinationPath, true);
Console.WriteLine($"Backed up {sourcePath} to {destinationPath}");

// Get file information
FileInfo fileInfo = new FileInfo(destinationPath);
Console.WriteLine($"Backup size: {fileInfo.Length} bytes");
}
catch (Exception ex)
{
Console.WriteLine($"Backup failed: {ex.Message}");
}
}
}

// Example usage
public void BackupExample()
{
FileBackup backup = new FileBackup();
backup.BackupFile(
@"C:\projects\important-document.docx",
@"C:\backups\documents"
);
}

Output:

Backed up C:\projects\important-document.docx to C:\backups\documents\important-document_20230925_143512.docx
Backup size: 24576 bytes

Best Practices for File Operations

When working with files in C#, keep these best practices in mind:

  1. Always use exception handling: File operations are prone to errors due to permissions, locks, or network issues.

  2. Dispose of resources properly: Use the using statement for objects that implement IDisposable like StreamReader and StreamWriter.

  3. Check file existence: Before performing operations, verify if files exist where appropriate.

  4. Use Path methods for path operations: Always use Path.Combine() instead of string concatenation for paths.

  5. Consider async operations for large files: Use the async versions of file operations (ReadAllTextAsync, etc.) for better performance.

  6. Be careful with file permissions: Always ensure your application has appropriate permissions.

  7. Handle file locks: Be prepared to handle scenarios where files are locked by other processes.

  8. Use relative paths when appropriate: This makes your application more portable.

Summary

In this tutorial, we've covered the essential file operations in C# including:

  • Checking if files exist
  • Creating files
  • Reading from files using different approaches
  • Writing to files and appending content
  • Copying and moving files
  • Deleting files
  • Getting detailed file information
  • Real-world examples with logging and backup systems

File operations are a fundamental part of many applications. C# provides a rich set of tools through the System.IO namespace that make it straightforward to work with files in a safe and efficient manner.

Exercises

To practice your file handling skills, try these exercises:

  1. Create a simple text editor application that can open, edit, and save text files.
  2. Implement a file merger that combines multiple text files into a single file.
  3. Create a file monitoring tool that watches a directory and logs any file changes.
  4. Build a CSV file processor that can read, modify, and write CSV data.
  5. Implement a file encryption/decryption utility using simple XOR encryption.

Additional Resources

Remember that file operations should always be performed with proper exception handling and security considerations in mind. Happy coding!



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)