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:

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:

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()

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

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

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

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

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

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

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

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

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

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

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

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:

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
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:

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!

💡 Found a typo or mistake? Click "Edit this page" to suggest a correction. Your feedback is greatly appreciated!