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:
- Creates a log file if it doesn't exist
- Appends log entries with timestamps
- 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:
-
Always use exception handling: File operations are prone to errors due to permissions, locks, or network issues.
-
Dispose of resources properly: Use the
using
statement for objects that implementIDisposable
likeStreamReader
andStreamWriter
. -
Check file existence: Before performing operations, verify if files exist where appropriate.
-
Use Path methods for path operations: Always use
Path.Combine()
instead of string concatenation for paths. -
Consider async operations for large files: Use the async versions of file operations (
ReadAllTextAsync
, etc.) for better performance. -
Be careful with file permissions: Always ensure your application has appropriate permissions.
-
Handle file locks: Be prepared to handle scenarios where files are locked by other processes.
-
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:
- Create a simple text editor application that can open, edit, and save text files.
- Implement a file merger that combines multiple text files into a single file.
- Create a file monitoring tool that watches a directory and logs any file changes.
- Build a CSV file processor that can read, modify, and write CSV data.
- Implement a file encryption/decryption utility using simple XOR encryption.
Additional Resources
- Microsoft Docs: File and Stream I/O
- C# FileInfo Class
- C# File Class
- Best Practices for Using Strings in .NET
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!