Lesson 22 — Reading and Writing Files
File Handling
C# file IO with System.IO is straightforward for most tasks. The File and StreamWriter/StreamReader classes cover the common cases cleanly.
CSHARP — File class — simple API
using System.IO;
// Write all lines at once (simplest):
File.WriteAllLines("learners.txt", new[] {
"Thandi Mokoena,Java,74.5",
"Sipho Dlamini,Python,81.0",
"Lerato Khumalo,SQL,68.0"
});
// Append:
File.AppendAllText("learners.txt", "Bongani Nkosi,C#,88.5\n");
// Read all lines:
string[] lines = File.ReadAllLines("learners.txt");
foreach (var line in lines)
Console.WriteLine(line);
// Read as single string:
string content = File.ReadAllText("learners.txt");
Console.WriteLine($"Total chars: {content.Length}");
StreamWriter for Large Files
CSHARP — StreamWriter/Reader
// using block — guarantees Close() is called:
using (var writer = new StreamWriter("log.txt", append: true)) {
writer.WriteLine($"[{DateTime.Now:yyyy-MM-dd HH:mm:ss}] Programme started.");
writer.WriteLine("=".PadRight(50, '='));
}
// Reading line by line (efficient for large files):
using (var reader = new StreamReader("learners.txt")) {
string? line;
int lineNum = 0;
while ((line = reader.ReadLine()) != null) {
lineNum++;
var parts = line.Split(',');
if (parts.Length == 3)
Console.WriteLine($"{lineNum}. {parts[0]} | {parts[1]} | {parts[2]}%");
}
}
File Checks and Path Handling
CSHARP — File checks
// Check before operating:
if (!File.Exists("config.txt")) {
File.WriteAllText("config.txt", "MaxLearners=30\n");
Console.WriteLine("Config file created.");
}
// Path handling — use Path.Combine for cross-platform paths:
string folder = "data";
string file = "learners.csv";
string fullPath = Path.Combine(folder, file);
Directory.CreateDirectory(folder); // create if not exists
Console.WriteLine($"Saving to: {fullPath}");
Practice Task
Your Turn
Write a LearnerRegistry: SaveToFile(List<Learner> learners, string path) writes CSV lines; LoadFromFile(string path) reads them back and returns a List. Handle FileNotFoundException, IOException, and FormatException. Test by saving 5 learners, clearing the list, reloading, and printing each.
Common Mistakes
- Not using using blocks — files may not close if an exception occurs.
- File.ReadAllLines on huge files — loads everything into memory. Use StreamReader for streaming.
- Hardcoded backslash paths on Windows — use Path.Combine for cross-platform.
- Not handling NumberFormatException when parsing numeric columns.
Professional Tip
Always handle the FileNotFoundException separately from IOException — they indicate different problems (file doesn't exist vs IO error) and need different responses.
Mini Quiz
What does File.WriteAllLines() do if the file already exists?
WriteAllLines (and WriteAllText) overwrites the file. Use File.AppendAllText or StreamWriter with append:true to add to an existing file.