Working with files and directories is a fundamental aspect of many applications. Whether you're developing a simple console app or a complex enterprise solution, understanding how to manipulate the file system is essential. In this tutorial, we'll delve deep into how to work with files and directories in C#, complete with examples, use cases, and a real-world application.
The ability to interact with the file system allows applications to store data persistently, read configuration files, log events, and much more. C# provides robust classes within the System.IO
namespace to handle file and directory operations seamlessly.
System.IO
NamespaceThe System.IO
namespace contains types that allow reading and writing to files and data streams, and types that provide basic file and directory support.
Key classes include:
File
: Provides static methods for creating, copying, deleting, moving, and opening files.FileInfo
: Provides instance methods for the same operations as the File
class, but the methods are instance-based.Directory
: Provides static methods for creating, moving, and enumerating through directories and subdirectories.DirectoryInfo
: Provides instance methods for the same operations as the Directory
class.StreamReader
and StreamWriter
: For reading from and writing to streams.FileStream
: Provides a stream for a file, supporting both synchronous and asynchronous read and write operations.To create a file, you can use the File.Create
method or the FileStream
class.
File.Create
:using System.IO;
class Program
{
static void Main()
{
string path = @"C:\temp\myfile.txt";
File.Create(path).Dispose(); // Dispose to release the handle
}
}
File.Create
method creates a file at the specified path.Dispose()
or use a using statement to release the file handle immediately.You can write to a file using the StreamWriter
class or the File.WriteAllText
method.
StreamWriter
:using System.IO;
class Program
{
static void Main()
{
string path = @"C:\temp\myfile.txt";
using (StreamWriter writer = new StreamWriter(path))
{
writer.WriteLine("Hello, World!");
}
}
}
StreamWriter
writes characters to a stream in a particular encoding.using
statement ensures the StreamWriter
is disposed of properly.To read from a file, use the StreamReader
class or File.ReadAllText
.
StreamReader
:using System;
using System.IO;
class Program
{
static void Main()
{
string path = @"C:\temp\myfile.txt";
using (StreamReader reader = new StreamReader(path))
{
string content = reader.ReadToEnd();
Console.WriteLine(content);
}
}
}
StreamReader
reads characters from a byte
stream in a particular encoding.ReadToEnd
reads the stream from the current position to the end.To append text to an existing file, you can use StreamWriter
with true as the second parameter or File.AppendAllText
.
StreamWriter
to append:using System.IO;
class Program
{
static void Main()
{
string path = @"C:\temp\myfile.txt";
using (StreamWriter writer = new StreamWriter(path, true))
{
writer.WriteLine("Appending a new line.");
}
}
}
Explanation:
true
to StreamWriter
opens the file in append mode.To delete a file, use the File.Delete
method.
using System.IO;
class Program
{
static void Main()
{
string path = @"C:\temp\myfile.txt";
if (File.Exists(path))
{
File.Delete(path);
Console.WriteLine("File deleted.");
}
else
{
Console.WriteLine("File does not exist.");
}
}
}
Use the Directory.CreateDirectory
method to create a directory.
using System.IO;
class Program
{
static void Main()
{
string path = @"C:\temp\myfolder";
Directory.CreateDirectory(path);
}
}
To list directories and files, use methods like Directory.GetFiles
and Directory.GetDirectories
.
using System;
using System.IO;
class Program
{
static void Main()
{
string path = @"C:\temp";
// List all files
string[] files = Directory.GetFiles(path);
Console.WriteLine("Files:");
foreach (string file in files)
{
Console.WriteLine(file);
}
// List all directories
string[] directories = Directory.GetDirectories(path);
Console.WriteLine("\nDirectories:");
foreach (string directory in directories)
{
Console.WriteLine(directory);
}
}
}
GetFiles
retrieves the names of files in a specified directory.GetDirectories
retrieves the names of subdirectories.using System.IO;
class Program
{
static void Main()
{
string sourceDir = @"C:\temp\myfolder";
string destDir = @"C:\temp\mynewfolder";
if (Directory.Exists(sourceDir))
{
Directory.Move(sourceDir, destDir);
Console.WriteLine("Directory moved.");
}
else
{
Console.WriteLine("Source directory does not exist.");
}
}
}
using System.IO;
class Program
{
static void Main()
{
string path = @"C:\temp\myfolder";
if (Directory.Exists(path))
{
Directory.Delete(path, true); // 'true' to delete subdirectories and files
Console.WriteLine("Directory deleted.");
}
else
{
Console.WriteLine("Directory does not exist.");
}
}
}
Directory.Move
moves a directory to a new location.Directory.Delete
deletes a directory. The second parameter indicates whether to delete subdirectories and files.The FileInfo
and DirectoryInfo
classes provide instance methods for file and directory operations and offer additional properties.
using System;
using System.IO;
class Program
{
static void Main()
{
string filePath = @"C:\temp\myfile.txt";
FileInfo fileInfo = new FileInfo(filePath);
if (fileInfo.Exists)
{
Console.WriteLine("File Size: " + fileInfo.Length);
Console.WriteLine("Created On: " + fileInfo.CreationTime);
Console.WriteLine("Last Accessed: " + fileInfo.LastAccessTime);
}
else
{
Console.WriteLine("File does not exist.");
}
}
}
Explanation:
FileInfo
provides properties like Length
, CreationTime
, and LastAccessTime
.Let's build a simple application that logs messages to daily log files and archives old logs.
using System;
using System.IO;
class LogManager
{
private string logDirectory;
private string archiveDirectory;
public LogManager(string logDir)
{
logDirectory = logDir;
archiveDirectory = Path.Combine(logDirectory, "Archive");
// Ensure directories exist
Directory.CreateDirectory(logDirectory);
Directory.CreateDirectory(archiveDirectory);
}
public void WriteLog(string message)
{
string logFile = Path.Combine(logDirectory, DateTime.Now.ToString("yyyy-MM-dd") + ".log");
using (StreamWriter writer = new StreamWriter(logFile, true))
{
writer.WriteLine($"{DateTime.Now:HH:mm:ss} - {message}");
}
}
public void ArchiveOldLogs(int days)
{
string[] logFiles = Directory.GetFiles(logDirectory, "*.log");
foreach (string file in logFiles)
{
FileInfo fileInfo = new FileInfo(file);
if (fileInfo.CreationTime < DateTime.Now.AddDays(-days))
{
string archivedPath = Path.Combine(archiveDirectory, fileInfo.Name);
if (File.Exists(archivedPath))
{
File.Delete(archivedPath);
}
File.Move(file, archivedPath);
Console.WriteLine($"Archived: {fileInfo.Name}");
}
}
}
}
class Program
{
static void Main()
{
LogManager logManager = new LogManager(@"C:\temp\logs");
// Write some logs
logManager.WriteLog("Application started.");
logManager.WriteLog("Performing some operations.");
logManager.WriteLog("Application ended.");
// Archive logs older than 7 days
logManager.ArchiveOldLogs(7);
}
}
LogManager
Class:WriteLog
writes messages to a daily log file.ArchiveOldLogs
moves logs older than a specified number of days to an archive directory.LogManager
with the desired log directory.WriteLog
to log messages.ArchiveOldLogs
to archive old logs.Use Cases:
System.IO
Namespace: Essential for file and directory operations in C#.File
vs. FileInfo
: File
provides static methods; FileInfo
provides instance methods with additional properties.Directory
vs. DirectoryInfo
: Similar to File
and FileInfo
, but for directories.StreamReader
and StreamWriter
: For reading from and writing to text files.Using
Statements: Ensure resources like file handles are released promptly.Path
class to handle file and directory paths efficiently and avoid hardcoding separators.Working with files and directories is a crucial skill for any C# developer. The System.IO namespace provides all the necessary classes and methods to create, read, write, move, and delete files and directories. Understanding how to leverage these tools allows you to manage data storage, configuration, logging, and more effectively. By applying these concepts, as demonstrated in the log file manager example, you can build robust applications that interact seamlessly with the file system.