File and Directory Basics
Working with files and directories is one of the clearest ways to move from pure language syntax into real application behavior. File-system code deals with external state, permissions, missing paths, encoding, and failure cases that do not exist in isolated in-memory examples.
Original Microsoft Learn reference: File and stream I/O.
That makes it a good place to practice defensive programming.
Common file-system tasks
Practical C# programs often need to:
- build file paths safely
- create or read text files
- enumerate directories
- check whether files or directories exist
- create folders if needed
- handle missing resources and permission problems
A simple example
string path = Path.Combine(Environment.CurrentDirectory, "notes.txt");
File.WriteAllText(path, "Hello file");
Console.WriteLine(File.ReadAllText(path));This shows the basic shape of file work:
- create a path
- write content
- read content back
Why Path.Combine matters
You should usually avoid building file paths by hand with string concatenation.
string path = Path.Combine("data", "reports", "summary.txt");Path.Combine is safer and clearer because it handles separators correctly for the platform.
A more practical example
string directory = Path.Combine(Environment.CurrentDirectory, "output");
Directory.CreateDirectory(directory);
string filePath = Path.Combine(directory, "log.txt");
File.AppendAllText(filePath, $"Started at {DateTime.Now}\n");
Console.WriteLine(File.ReadAllText(filePath));This looks more like real application code because it creates a folder when needed and appends to a simple log file.
A mental model
flowchart LR
A["Build safe path"] --> B["Ensure directory exists"]
B --> C["Read or write file"]
C --> D["Handle failures if needed"]Real file work is never only about the happy path.
File operations can fail
File-system code may fail for many reasons:
- the file does not exist
- the directory does not exist
- the process lacks permission
- the file is locked
- the path is invalid
- the disk or external storage is unavailable
That is why practical file code often needs validation and exception handling.
Reading defensively
string path = Path.Combine(Environment.CurrentDirectory, "settings.json");
if (File.Exists(path))
{
string content = File.ReadAllText(path);
Console.WriteLine(content);
}
else
{
Console.WriteLine("Settings file not found.");
}This is not the only valid approach, but it shows the idea that external resources require deliberate handling.
Files versus directories
It helps to keep the API surfaces separate in your mind:
Fileis for file-specific operationsDirectoryis for folder-specific operationsPathis for path construction and inspection
These types are often used together.
Practical guidance
Good file-system code usually:
- uses
Path.Combineinstead of manual path strings - validates assumptions about file existence when appropriate
- handles exceptions from external failures
- avoids hard-coded machine-specific paths when possible
- thinks about encoding, overwriting, and append behavior deliberately
Common beginner mistakes
- Concatenating paths with raw string separators.
- Assuming files always exist.
- Ignoring permission or lock failures.
- Treating file-system code like ordinary in-memory logic with no environmental risk.
Summary
- file and directory code brings external state into your program
Path,File, andDirectoryeach play different roles- practical code should assume file operations can fail
Path.Combineis the normal safe way to build paths- defensive checks and error handling matter much more here than in toy examples
Practice
Write a small program that creates a folder, writes a text file into it, then reads the file back.
As a second exercise, list three realistic reasons why that program could fail on another machine even if the code itself is correct.