S5.0 What This Teaches
- Reading and writing text files with
Fileconvenience methods - Streaming reads and writes with
StreamReader/StreamWriter - Working with paths using
PathandDirectoryInfo - Directory enumeration
- Reading and writing binary data
S5.1 File Convenience Methods
using System.IO;
// Write all text at once (creates or overwrites)
File.WriteAllText("notes.txt", "Hello, file!");
// Append text
File.AppendAllText("notes.txt", "\nSecond line.");
// Read all text
string content = File.ReadAllText("notes.txt");
Console.WriteLine(content);
// Read all lines into an array
string[] lines = File.ReadAllLines("notes.txt");
foreach (string line in lines)
Console.WriteLine(line);
// Write multiple lines
File.WriteAllLines("list.txt", new[] { "alpha", "beta", "gamma" });
File convenience methods are best for small files that fit in memory.
They open, read/write, and close in one call. Use streaming APIs for large files.
S5.2 StreamReader and StreamWriter
// Write line by line
using var writer = new StreamWriter("output.txt");
for (int i = 1; i <= 5; i++)
writer.WriteLine($"Line {i}");
// writer.Dispose() called automatically at end of scope
// Read line by line - efficient for large files
using var reader = new StreamReader("output.txt");
string? line;
while ((line = reader.ReadLine()) != null)
Console.WriteLine(line);
// Append to existing file
using var appender = new StreamWriter("output.txt", append: true);
appender.WriteLine("Appended line");
S5.3 Path and Directory Operations
string full = Path.GetFullPath("notes.txt");
string dir = Path.GetDirectoryName(full)!;
string name = Path.GetFileName(full); // "notes.txt"
string stem = Path.GetFileNameWithoutExtension(full); // "notes"
string ext = Path.GetExtension(full); // ".txt"
// Build paths in a platform-safe way
string path = Path.Combine(dir, "subdir", "file.txt");
// Test existence
bool fileExists = File.Exists("notes.txt");
bool dirExists = Directory.Exists("mydir");
// Create and delete
Directory.CreateDirectory("newdir");
Directory.Delete("newdir", recursive: false);
File.Delete("notes.txt");
// Enumerate files
foreach (string f in Directory.EnumerateFiles(".", "*.txt"))
Console.WriteLine(Path.GetFileName(f));
S5.4 Binary Files
// Write bytes
byte[] data = { 1, 2, 3, 4, 5 };
File.WriteAllBytes("data.bin", data);
// Read bytes
byte[] read = File.ReadAllBytes("data.bin");
Console.WriteLine(read.Length); // 5
// BinaryWriter / BinaryReader for typed data
using var bw = new BinaryWriter(File.OpenWrite("record.bin"));
bw.Write(42); // int (4 bytes)
bw.Write(3.14); // double (8 bytes)
bw.Write("hello"); // length-prefixed string
using var br = new BinaryReader(File.OpenRead("record.bin"));
Console.WriteLine(br.ReadInt32()); // 42
Console.WriteLine(br.ReadDouble()); // 3.14
Console.WriteLine(br.ReadString()); // hello
S5.5 Example - All Together
// File I/O - write CSV and read it back, counting lines.
using System.IO;
string csvPath = "scores.csv";
// Write CSV
var records = new[] { ("Alice", 92), ("Bob", 78), ("Carol", 95) };
using (var w = new StreamWriter(csvPath))
{
w.WriteLine("Name,Score");
foreach (var (name, score) in records)
w.WriteLine($"{name},{score}");
}
// Read and process
int count = 0;
int total = 0;
using (var r = new StreamReader(csvPath))
{
r.ReadLine(); // skip header
string? line;
while ((line = r.ReadLine()) != null)
{
var parts = line.Split(',');
total += int.Parse(parts[1]);
count++;
}
}
Console.WriteLine($"Average score: {total / (double)count:F1}");
Average score: 88.3
S5.6 Exercise
Exercise
- Write a program that creates a file, writes 10 lines to it with
StreamWriter, then reads and prints each line withStreamReader. - Use
Directory.EnumerateFilesto list all.csfiles in the current directory (or a test directory). Print the total line count across all files. - Write and read a binary file using
BinaryWriterandBinaryReaderto store an array ofdoublevalues. Verify the round-trip is lossless.
S5.7 Common Mistakes
Forgetting to close or dispose file handles
using leaves file handles open until
the GC finalizes the object, which is non-deterministic. On Windows this
prevents other processes from opening the file. Always use using.
Using + for path concatenation
string path = dir + "\\" + name; // breaks on Linux (different separator)
string path = Path.Combine(dir, name); // correct - portable
Reading a huge file with ReadAllText
File.ReadAllText loads the entire file into a string. For files
larger than a few MB, use StreamReader to process line by line,
or File.ReadLines which returns an IEnumerable<string>
and reads lazily.
S5.8 Key Terms
| Term | Meaning |
|---|---|
| File | Static class with convenience methods for common file operations |
| StreamReader | Reads characters from a byte stream; buffers for efficiency |
| StreamWriter | Writes characters to a byte stream; buffers writes |
| Path | Static class for manipulating path strings portably |
| Directory | Static class for directory creation, deletion, and enumeration |
| BinaryReader/Writer | Reads/writes primitive types as raw bytes |
| using | Ensures Dispose() on streams; guarantees handle is released |
| File.ReadLines | Lazy enumeration of lines; preferred over ReadAllLines for large files |