Skip to main content

File I/O

File I/O (Input/Output) operations are essential for reading from and writing to files in C#. The .NET Framework provides a rich set of classes for working with files and directories.

File and Directory Operations​

File Class​

The File class provides static methods for creating, copying, deleting, moving, and opening files.

// Check if a file exists
bool exists = File.Exists("data.txt");

// Create a new file (overwrites if exists) and write text
File.WriteAllText("output.txt", "Hello, World!");

// Append text to a file (creates if doesn't exist)
File.AppendAllText("log.txt", $"{DateTime.Now}: Application started\n");

// Read all text from a file
string content = File.ReadAllText("data.txt");

// Read all lines from a file into a string array
string[] lines = File.ReadAllLines("data.txt");

// Write all lines to a file
File.WriteAllLines("output.txt", new[] { "Line 1", "Line 2", "Line 3" });

// Copy a file (overwrite if exists)
File.Copy("source.txt", "destination.txt", true);

// Move a file (rename)
File.Move("old.txt", "new.txt");

// Delete a file
File.Delete("temp.txt");

// Get file attributes
FileAttributes attributes = File.GetAttributes("data.txt");
bool isReadOnly = (attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly;

// Set file attributes
File.SetAttributes("data.txt", FileAttributes.ReadOnly);

// Get file creation, access, and modification times
DateTime created = File.GetCreationTime("data.txt");
DateTime accessed = File.GetLastAccessTime("data.txt");
DateTime modified = File.GetLastWriteTime("data.txt");

// Open a file and return a FileStream
using (FileStream fs = File.Open("data.txt", FileMode.Open, FileAccess.Read))
{
// Use the FileStream...
}

// Create a StreamReader for a file
using (StreamReader reader = File.OpenText("data.txt"))
{
// Use the StreamReader...
}

// Create a StreamWriter for a file
using (StreamWriter writer = File.CreateText("output.txt"))
{
// Use the StreamWriter...
}

Directory Class​

The Directory class provides static methods for creating, moving, and enumerating through directories and subdirectories.

// Check if a directory exists
bool exists = Directory.Exists("logs");

// Create a directory
Directory.CreateDirectory("logs");

// Get the current directory
string currentDir = Directory.GetCurrentDirectory();

// Get the parent directory
string parentDir = Directory.GetParent(currentDir).FullName;

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

// Get files with a specific pattern
string[] textFiles = Directory.GetFiles("logs", "*.txt");

// Get files with a specific pattern, including subdirectories
string[] allTextFiles = Directory.GetFiles("logs", "*.txt", SearchOption.AllDirectories);

// Get all directories in a directory
string[] dirs = Directory.GetDirectories("data");

// Get directories with a specific pattern
string[] backupDirs = Directory.GetDirectories("data", "backup*");

// Get all subdirectories recursively
string[] allSubDirs = Directory.GetDirectories("data", "*", SearchOption.AllDirectories);

// Move a directory
Directory.Move("old_logs", "new_logs");

// Delete an empty directory
Directory.Delete("temp");

// Delete a directory and all its contents
Directory.Delete("temp", true);

// Get directory creation, access, and modification times
DateTime created = Directory.GetCreationTime("logs");
DateTime accessed = Directory.GetLastAccessTime("logs");
DateTime modified = Directory.GetLastWriteTime("logs");

Path Class​

The Path class provides methods for processing directory and file paths.

// Combine path parts
string fullPath = Path.Combine("data", "users", "user1.txt"); // "data/users/user1.txt" or "data\users\user1.txt"

// Get the file name from a path
string fileName = Path.GetFileName("data/users/user1.txt"); // "user1.txt"

// Get the file name without extension
string fileNameWithoutExt = Path.GetFileNameWithoutExtension("data/users/user1.txt"); // "user1"

// Get the file extension
string extension = Path.GetExtension("data/users/user1.txt"); // ".txt"

// Get the directory name
string dirName = Path.GetDirectoryName("data/users/user1.txt"); // "data/users"

// Get the full path (resolves relative paths)
string absolutePath = Path.GetFullPath("../data/users/user1.txt");

// Get a temporary file name
string tempFile = Path.GetTempFileName();

// Get the temporary directory path
string tempDir = Path.GetTempPath();

// Get the root directory
string rootDir = Path.GetPathRoot("C:/data/users/user1.txt"); // "C:/"

// Check if a path has an extension
bool hasExtension = Path.HasExtension("data.txt"); // true

// Change the extension of a path
string newPath = Path.ChangeExtension("data.txt", ".csv"); // "data.csv"

// Get a random file name
string randomFileName = Path.GetRandomFileName();

// Get the directory separator character
char separator = Path.DirectorySeparatorChar; // '/' on Unix, '\' on Windows

// Get the invalid characters for file names
char[] invalidChars = Path.GetInvalidFileNameChars();

FileInfo and DirectoryInfo Classes​

FileInfo and DirectoryInfo provide instance methods for working with files and directories.

// Create a FileInfo object
FileInfo file = new FileInfo("data.txt");

// Check if the file exists
bool exists = file.Exists;

// Get file properties
string name = file.Name;
string directory = file.DirectoryName;
string fullPath = file.FullName;
long size = file.Length;
bool isReadOnly = file.IsReadOnly;
DateTime created = file.CreationTime;
DateTime modified = file.LastWriteTime;

// Create a new file
using (FileStream fs = file.Create())
{
// Use the FileStream...
}

// Open a file for reading
using (FileStream fs = file.OpenRead())
{
// Use the FileStream...
}

// Open a file for writing
using (FileStream fs = file.OpenWrite())
{
// Use the FileStream...
}

// Create a StreamReader for the file
using (StreamReader reader = file.OpenText())
{
// Use the StreamReader...
}

// Create a StreamWriter for the file
using (StreamWriter writer = file.CreateText())
{
// Use the StreamWriter...
}

// Copy the file
FileInfo copy = file.CopyTo("copy.txt", true);

// Move/rename the file
file.MoveTo("new_name.txt");

// Delete the file
file.Delete();

// Create a DirectoryInfo object
DirectoryInfo dir = new DirectoryInfo("logs");

// Check if the directory exists
exists = dir.Exists;

// Get directory properties
name = dir.Name;
fullPath = dir.FullName;
DirectoryInfo parent = dir.Parent;
created = dir.CreationTime;

// Create the directory
dir.Create();

// Get files in the directory
FileInfo[] files = dir.GetFiles();

// Get files with a specific pattern
FileInfo[] textFiles = dir.GetFiles("*.txt");

// Get files with a specific pattern, including subdirectories
FileInfo[] allTextFiles = dir.GetFiles("*.txt", SearchOption.AllDirectories);

// Get subdirectories
DirectoryInfo[] subDirs = dir.GetDirectories();

// Get subdirectories with a specific pattern
DirectoryInfo[] backupDirs = dir.GetDirectories("backup*");

// Move/rename the directory
dir.MoveTo("new_logs");

// Delete the directory
dir.Delete(); // Fails if not empty
dir.Delete(true); // Deletes all contents

Reading and Writing Files​

StreamReader and StreamWriter​

StreamReader and StreamWriter are used for reading from and writing to text files.

// Reading a text file line by line
using (StreamReader reader = new StreamReader("data.txt"))
{
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
}

// Reading a text file all at once
using (StreamReader reader = new StreamReader("data.txt"))
{
string content = reader.ReadToEnd();
Console.WriteLine(content);
}

// Reading a specific number of characters
using (StreamReader reader = new StreamReader("data.txt"))
{
char[] buffer = new char[1024];
int charsRead = reader.Read(buffer, 0, buffer.Length);
Console.WriteLine(new string(buffer, 0, charsRead));
}

// Writing to a text file
using (StreamWriter writer = new StreamWriter("output.txt"))
{
writer.WriteLine("Line 1");
writer.WriteLine("Line 2");
writer.WriteLine("Line 3");
}

// Appending to a text file
using (StreamWriter writer = new StreamWriter("log.txt", true))
{
writer.WriteLine($"{DateTime.Now}: Application started");
}

// Writing with specific encoding
using (StreamWriter writer = new StreamWriter("output.txt", false, Encoding.UTF8))
{
writer.WriteLine("Text with UTF-8 encoding");
}

// Reading with specific encoding
using (StreamReader reader = new StreamReader("data.txt", Encoding.UTF8))
{
string content = reader.ReadToEnd();
Console.WriteLine(content);
}

FileStream​

FileStream provides a stream for reading from and writing to files.

// Creating a file and writing bytes
using (FileStream fs = new FileStream("data.bin", FileMode.Create, FileAccess.Write))
{
byte[] data = { 0x48, 0x65, 0x6C, 0x6C, 0x6F }; // "Hello" in ASCII
fs.Write(data, 0, data.Length);
}

// Opening a file and reading bytes
using (FileStream fs = new FileStream("data.bin", FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[1024];
int bytesRead = fs.Read(buffer, 0, buffer.Length);

// Process the bytes...
for (int i = 0; i < bytesRead; i++)
{
Console.Write($"{buffer[i]:X2} ");
}
}

// Seeking to a specific position
using (FileStream fs = new FileStream("data.bin", FileMode.Open, FileAccess.ReadWrite))
{
// Seek to the 10th byte
fs.Seek(10, SeekOrigin.Begin);

// Read from that position
int byteValue = fs.ReadByte();

// Seek to the end
fs.Seek(0, SeekOrigin.End);

// Append data
byte[] data = { 0x21 }; // "!" in ASCII
fs.Write(data, 0, data.Length);

// Seek relative to current position
fs.Seek(-5, SeekOrigin.Current);
}

// Using FileStream with different modes
using (FileStream fs = new FileStream("data.bin", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read))
{
// FileMode.OpenOrCreate - Opens if exists, creates if doesn't
// FileAccess.ReadWrite - Allows reading and writing
// FileShare.Read - Allows other processes to read the file while open

// File operations...
}

BinaryReader and BinaryWriter​

BinaryReader and BinaryWriter are used for reading and writing primitive data types as binary values.

// Writing binary data
using (FileStream fs = new FileStream("data.bin", FileMode.Create))
using (BinaryWriter writer = new BinaryWriter(fs))
{
writer.Write(42); // Write an int
writer.Write(3.14159); // Write a double
writer.Write("Hello"); // Write a string
writer.Write(true); // Write a boolean
writer.Write((byte)255); // Write a byte
}

// Reading binary data
using (FileStream fs = new FileStream("data.bin", FileMode.Open))
using (BinaryReader reader = new BinaryReader(fs))
{
int intValue = reader.ReadInt32();
double doubleValue = reader.ReadDouble();
string stringValue = reader.ReadString();
bool boolValue = reader.ReadBoolean();
byte byteValue = reader.ReadByte();

Console.WriteLine($"Int: {intValue}, Double: {doubleValue}, String: {stringValue}, Bool: {boolValue}, Byte: {byteValue}");
}

// Reading until end of file
using (FileStream fs = new FileStream("data.bin", FileMode.Open))
using (BinaryReader reader = new BinaryReader(fs))
{
try
{
while (true)
{
byte value = reader.ReadByte();
Console.Write($"{value:X2} ");
}
}
catch (EndOfStreamException)
{
// Reached the end of the file
Console.WriteLine("\nEnd of file reached.");
}
}

MemoryStream​

MemoryStream provides a stream that uses memory as a backing store instead of a file.

// Creating a MemoryStream and writing to it
using (MemoryStream ms = new MemoryStream())
{
// Write data to the memory stream
byte[] data = Encoding.UTF8.GetBytes("Hello, World!");
ms.Write(data, 0, data.Length);

// Reset the position to the beginning
ms.Position = 0;

// Read data from the memory stream
byte[] buffer = new byte[ms.Length];
ms.Read(buffer, 0, buffer.Length);

// Convert bytes back to string
string result = Encoding.UTF8.GetString(buffer);
Console.WriteLine(result); // "Hello, World!"

// Get the bytes from the memory stream
byte[] allBytes = ms.ToArray();

// Write the memory stream to a file
File.WriteAllBytes("output.bin", allBytes);
}

// Using MemoryStream as a temporary buffer
using (MemoryStream ms = new MemoryStream())
{
// Create a writer that writes to the memory stream
using (StreamWriter writer = new StreamWriter(ms, Encoding.UTF8, 1024, true))
{
writer.WriteLine("Line 1");
writer.WriteLine("Line 2");
writer.Flush(); // Ensure all data is written to the underlying stream

// Get the current position
long position = ms.Position;

// Reset to beginning
ms.Position = 0;

// Create a reader that reads from the memory stream
using (StreamReader reader = new StreamReader(ms, Encoding.UTF8, false, 1024, true))
{
string content = reader.ReadToEnd();
Console.WriteLine(content);
}
}
}

Asynchronous File I/O​

Async File Operations​

The .NET Framework provides asynchronous versions of many file operations.

// Async file reading
public async Task<string> ReadFileAsync(string filePath)
{
using (StreamReader reader = new StreamReader(filePath))
{
return await reader.ReadToEndAsync();
}
}

// Async file writing
public async Task WriteFileAsync(string filePath, string content)
{
using (StreamWriter writer = new StreamWriter(filePath))
{
await writer.WriteAsync(content);
}
}

// Async file copy
public async Task CopyFileAsync(string sourcePath, string destinationPath)
{
using (FileStream sourceStream = new FileStream(sourcePath, FileMode.Open, FileAccess.Read))
using (FileStream destinationStream = new FileStream(destinationPath, FileMode.Create, FileAccess.Write))
{
await sourceStream.CopyToAsync(destinationStream);
}
}

// Using File class async methods
public async Task FileClassAsyncExample()
{
// Read all text asynchronously
string content = await File.ReadAllTextAsync("data.txt");

// Read all lines asynchronously
string[] lines = await File.ReadAllLinesAsync("data.txt");

// Read all bytes asynchronously
byte[] bytes = await File.ReadAllBytesAsync("data.bin");

// Write all text asynchronously
await File.WriteAllTextAsync("output.txt", "Hello, World!");

// Write all lines asynchronously
await File.WriteAllLinesAsync("output.txt", new[] { "Line 1", "Line 2", "Line 3" });

// Write all bytes asynchronously
await File.WriteAllBytesAsync("output.bin", new byte[] { 0x48, 0x65, 0x6C, 0x6C, 0x6F });
}

// Async file stream operations
public async Task FileStreamAsyncExample()
{
using (FileStream fs = new FileStream("data.bin", FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[1024];

// Read asynchronously
int bytesRead = await fs.ReadAsync(buffer, 0, buffer.Length);

// Process the bytes...
}

using (FileStream fs = new FileStream("output.bin", FileMode.Create, FileAccess.Write))
{
byte[] data = { 0x48, 0x65, 0x6C, 0x6C, 0x6F }; // "Hello" in ASCII

// Write asynchronously
await fs.WriteAsync(data, 0, data.Length);
}
}

Async Stream Reading and Writing​

// Async stream reading line by line
public async Task ReadLinesAsync(string filePath)
{
using (StreamReader reader = new StreamReader(filePath))
{
string line;
while ((line = await reader.ReadLineAsync()) != null)
{
Console.WriteLine(line);
}
}
}

// Async stream writing
public async Task WriteLinesAsync(string filePath, IEnumerable<string> lines)
{
using (StreamWriter writer = new StreamWriter(filePath))
{
foreach (string line in lines)
{
await writer.WriteLineAsync(line);
}
}
}

// Processing a large file asynchronously
public async Task ProcessLargeFileAsync(string filePath)
{
using (StreamReader reader = new StreamReader(filePath))
{
// Buffer for reading chunks of text
char[] buffer = new char[4096];
int charsRead;

while ((charsRead = await reader.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
// Process the characters in the buffer
string chunk = new string(buffer, 0, charsRead);
// Do something with the chunk...
}
}
}

File Compression​

Using System.IO.Compression​

The System.IO.Compression namespace provides classes for compressing and decompressing files and streams.

// Compress a file
public void CompressFile(string sourceFile, string compressedFile)
{
using (FileStream sourceStream = new FileStream(sourceFile, FileMode.Open))
using (FileStream targetStream = new FileStream(compressedFile, FileMode.Create))
using (GZipStream compressionStream = new GZipStream(targetStream, CompressionMode.Compress))
{
sourceStream.CopyTo(compressionStream);
}
}

// Decompress a file
public void DecompressFile(string compressedFile, string targetFile)
{
using (FileStream sourceStream = new FileStream(compressedFile, FileMode.Open))
using (GZipStream decompressionStream = new GZipStream(sourceStream, CompressionMode.Decompress))
using (FileStream targetStream = new FileStream(targetFile, FileMode.Create))
{
decompressionStream.CopyTo(targetStream);
}
}

// Compress a string
public byte[] CompressString(string text)
{
byte[] inputBytes = Encoding.UTF8.GetBytes(text);

using (MemoryStream outputStream = new MemoryStream())
{
using (GZipStream compressionStream = new GZipStream(outputStream, CompressionMode.Compress, true))
{
compressionStream.Write(inputBytes, 0, inputBytes.Length);
}

return outputStream.ToArray();
}
}

// Decompress a byte array to a string
public string DecompressString(byte[] compressedData)
{
using (MemoryStream inputStream = new MemoryStream(compressedData))
using (GZipStream decompressionStream = new GZipStream(inputStream, CompressionMode.Decompress))
using (StreamReader reader = new StreamReader(decompressionStream, Encoding.UTF8))
{
return reader.ReadToEnd();
}
}

Working with ZIP Files​

// Create a ZIP file
public void CreateZipFile(string sourceDirectory, string zipFilePath)
{
ZipFile.CreateFromDirectory(sourceDirectory, zipFilePath);
}

// Extract a ZIP file
public void ExtractZipFile(string zipFilePath, string targetDirectory)
{
ZipFile.ExtractToDirectory(zipFilePath, targetDirectory);
}

// Create a ZIP file with options
public void CreateZipFileWithOptions(string sourceDirectory, string zipFilePath)
{
ZipFile.CreateFromDirectory(
sourceDirectory,
zipFilePath,
CompressionLevel.Optimal, // Compression level
false, // Include base directory
Encoding.UTF8 // Entry name encoding
);
}

// Extract a ZIP file with encoding
public void ExtractZipFileWithEncoding(string zipFilePath, string targetDirectory)
{
ZipFile.ExtractToDirectory(zipFilePath, targetDirectory, Encoding.UTF8);
}

// Working with ZIP archives
public void ManipulateZipArchive(string zipFilePath)
{
using (ZipArchive archive = ZipFile.Open(zipFilePath, ZipArchiveMode.Update))
{
// Add a file to the archive
ZipArchiveEntry entry = archive.CreateEntry("newfile.txt");
using (StreamWriter writer = new StreamWriter(entry.Open()))
{
writer.WriteLine("This is a new file in the ZIP archive.");
}

// Extract a specific file
ZipArchiveEntry existingEntry = archive.GetEntry("existingfile.txt");
if (existingEntry != null)
{
existingEntry.ExtractToFile("extracted.txt", true);
}

// Delete an entry
ZipArchiveEntry entryToDelete = archive.GetEntry("oldfile.txt");
if (entryToDelete != null)
{
entryToDelete.Delete();
}

// List all entries
foreach (ZipArchiveEntry archiveEntry in archive.Entries)
{
Console.WriteLine($"Name: {archiveEntry.Name}, Size: {archiveEntry.Length}, Modified: {archiveEntry.LastWriteTime}");
}
}
}

File Watching​

FileSystemWatcher​

The FileSystemWatcher class allows you to monitor a directory for changes to files and subdirectories.

// Create a FileSystemWatcher
public void WatchDirectory(string path)
{
// Create a new FileSystemWatcher
using (FileSystemWatcher watcher = new FileSystemWatcher())
{
// Set the directory to watch
watcher.Path = path;

// Watch for changes in LastWrite time and file/directory name
watcher.NotifyFilter = NotifyFilters.LastWrite
| NotifyFilters.FileName
| NotifyFilters.DirectoryName;

// Only watch text files
watcher.Filter = "*.txt";

// Add event handlers
watcher.Changed += OnChanged;
watcher.Created += OnCreated;
watcher.Deleted += OnDeleted;
watcher.Renamed += OnRenamed;

// Begin watching
watcher.EnableRaisingEvents = true;

// Wait for the user to quit the program
Console.WriteLine("Press 'q' to quit the watcher.");
while (Console.Read() != 'q') ;
}
}

// Event handlers
private static void OnChanged(object sender, FileSystemEventArgs e)
{
Console.WriteLine($"File: {e.FullPath} {e.ChangeType}");
}

private static void OnCreated(object sender, FileSystemEventArgs e)
{
Console.WriteLine($"File: {e.FullPath} created");
}

private static void OnDeleted(object sender, FileSystemEventArgs e)
{
Console.WriteLine($"File: {e.FullPath} deleted");
}

private static void OnRenamed(object sender, RenamedEventArgs e)
{
Console.WriteLine($"File: {e.OldFullPath} renamed to {e.FullPath}");
}

// Watch subdirectories
public void WatchDirectoryWithSubdirectories(string path)
{
using (FileSystemWatcher watcher = new FileSystemWatcher())
{
watcher.Path = path;
watcher.IncludeSubdirectories = true; // Watch subdirectories
watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;

// Event handlers...

watcher.EnableRaisingEvents = true;

// Wait for the user to quit the program
Console.WriteLine("Press 'q' to quit the watcher.");
while (Console.Read() != 'q') ;
}
}

File Security​

File Access Control​

// Get file security information
public void GetFileSecurity(string filePath)
{
FileSecurity security = File.GetAccessControl(filePath);

// Get the owner
IdentityReference owner = security.GetOwner(typeof(NTAccount));
Console.WriteLine($"Owner: {owner.Value}");

// Get access rules
AuthorizationRuleCollection rules = security.GetAccessRules(true, true, typeof(NTAccount));

foreach (FileSystemAccessRule rule in rules)
{
Console.WriteLine($"Identity: {rule.IdentityReference.Value}");
Console.WriteLine($"Access: {rule.FileSystemRights}");
Console.WriteLine($"Type: {rule.AccessControlType}");
Console.WriteLine();
}
}

// Set file security
public void SetFileSecurity(string filePath)
{
FileSecurity security = File.GetAccessControl(filePath);

// Add a new access rule
FileSystemAccessRule rule = new FileSystemAccessRule(
"Everyone", // Identity
FileSystemRights.Read, // Rights
AccessControlType.Allow // Allow or deny
);

security.AddAccessRule(rule);

// Set the modified security
File.SetAccessControl(filePath, security);
}

// Remove an access rule
public void RemoveAccessRule(string filePath, string identity)
{
FileSecurity security = File.GetAccessControl(filePath);

// Create a rule to remove
FileSystemAccessRule rule = new FileSystemAccessRule(
identity,
FileSystemRights.FullControl,
AccessControlType.Allow
);

// Remove the rule
security.RemoveAccessRule(rule);

// Set the modified security
File.SetAccessControl(filePath, security);
}

// Change the owner
public void ChangeOwner(string filePath, string newOwner)
{
FileSecurity security = File.GetAccessControl(filePath);

// Set the new owner
security.SetOwner(new NTAccount(newOwner));

// Apply the changes
File.SetAccessControl(filePath, security);
}

Encrypted File System (EFS)​

// Encrypt a file
public void EncryptFile(string filePath)
{
File.Encrypt(filePath);
}

// Decrypt a file
public void DecryptFile(string filePath)
{
File.Decrypt(filePath);
}

// Check if a file is encrypted
public bool IsFileEncrypted(string filePath)
{
FileAttributes attributes = File.GetAttributes(filePath);
return (attributes & FileAttributes.Encrypted) == FileAttributes.Encrypted;
}

Best Practices​

Error Handling​

// Proper error handling for file operations
public string ReadFileWithErrorHandling(string filePath)
{
try
{
return File.ReadAllText(filePath);
}
catch (FileNotFoundException ex)
{
Console.WriteLine($"File not found: {ex.Message}");
return string.Empty;
}
catch (DirectoryNotFoundException ex)
{
Console.WriteLine($"Directory not found: {ex.Message}");
return string.Empty;
}
catch (IOException ex)
{
Console.WriteLine($"I/O error: {ex.Message}");
return string.Empty;
}
catch (UnauthorizedAccessException ex)
{
Console.WriteLine($"Access denied: {ex.Message}");
return string.Empty;
}
catch (Exception ex)
{
Console.WriteLine($"Unexpected error: {ex.Message}");
return string.Empty;
}
}

// Using the using statement for proper resource disposal
public void WriteFileWithProperDisposal(string filePath, string content)
{
try
{
using (StreamWriter writer = new StreamWriter(filePath))
{
writer.Write(content);
} // StreamWriter is automatically disposed here
}
catch (Exception ex)
{
Console.WriteLine($"Error writing to file: {ex.Message}");
}
}

Performance Considerations​

// Buffered reading for better performance
public void ReadLargeFileEfficiently(string filePath)
{
const int BufferSize = 8192; // 8KB buffer

using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read, BufferSize))
using (BufferedStream bs = new BufferedStream(fs, BufferSize))
using (StreamReader reader = new StreamReader(bs))
{
string line;
while ((line = reader.ReadLine()) != null)
{
// Process the line...
}
}
}

// Using FileOptions for performance optimization
public void OptimizeFileAccess(string filePath)
{
// Sequential access optimization
using (FileStream fs = new FileStream(
filePath,
FileMode.Open,
FileAccess.Read,
FileShare.Read,
4096, // Buffer size
FileOptions.SequentialScan)) // Optimize for sequential access
{
// Read the file...
}

// Random access optimization
using (FileStream fs = new FileStream(
filePath,
FileMode.Open,
FileAccess.Read,
FileShare.Read,
4096,
FileOptions.RandomAccess)) // Optimize for random access
{
// Read the file...
}

// Asynchronous optimization
using (FileStream fs = new FileStream(
filePath,
FileMode.Open,
FileAccess.Read,
FileShare.Read,
4096,
FileOptions.Asynchronous)) // Optimize for asynchronous access
{
// Read the file asynchronously...
}
}

// Memory-mapped files for very large files
public void UseMemoryMappedFile(string filePath)
{
using (MemoryMappedFile mmf = MemoryMappedFile.CreateFromFile(filePath, FileMode.Open))
{
// Access a portion of the file
using (MemoryMappedViewAccessor accessor = mmf.CreateViewAccessor(0, 1024)) // First 1KB
{
// Read data
byte value = accessor.ReadByte(0);

// Write data
accessor.Write(10, (byte)65); // Write 'A' at offset 10
}

// Access the file as a stream
using (MemoryMappedViewStream stream = mmf.CreateViewStream())
{
// Use the stream...
byte[] buffer = new byte[100];
stream.Read(buffer, 0, buffer.Length);
}
}
}

File Path Handling​

// Safe file path handling
public string GetSafeFilePath(string basePath, string fileName)
{
// Validate and sanitize the file name
if (string.IsNullOrEmpty(fileName))
{
throw new ArgumentException("File name cannot be null or empty", nameof(fileName));
}

// Remove any invalid characters
string safeFileName = string.Join("_", fileName.Split(Path.GetInvalidFileNameChars()));

// Combine paths safely
string fullPath = Path.Combine(basePath, safeFileName);

// Ensure the resulting path is within the intended directory
string normalizedPath = Path.GetFullPath(fullPath);
string normalizedBasePath = Path.GetFullPath(basePath);

if (!normalizedPath.StartsWith(normalizedBasePath))
{
throw new SecurityException("Attempted path traversal attack");
}

return fullPath;
}

// Creating a unique file name
public string GetUniqueFileName(string directory, string fileName)
{
string fileNameOnly = Path.GetFileNameWithoutExtension(fileName);
string extension = Path.GetExtension(fileName);
string path = Path.Combine(directory, fileName);
int count = 1;

while (File.Exists(path))
{
string newFileName = $"{fileNameOnly}({count}){extension}";
path = Path.Combine(directory, newFileName);
count++;
}

return path;
}

Resources​