SyntaxStudy
Sign Up
C# StreamReader, StreamWriter, and Binary Streams
C# Beginner 1 min read

StreamReader, StreamWriter, and Binary Streams

When you need fine-grained control over reading and writing, or when dealing with large files that should not be loaded entirely into memory, `StreamReader` and `StreamWriter` provide line-by-line and character-level access. They wrap an underlying `Stream` and handle character encoding automatically. `FileStream` is the raw byte-level abstraction for file access. You specify `FileMode`, `FileAccess`, and `FileShare` to control how the file is opened. `BinaryReader` and `BinaryWriter` wrap a stream and let you read/write primitive .NET types (int, double, bool, etc.) directly in binary format, which is more efficient than text for structured data. All stream types implement `IDisposable`, so you should always use `using` statements or declarations to ensure the file handle is released. Buffered streams (`BufferedStream`) reduce the number of OS-level I/O calls by batching small reads and writes, significantly improving performance for sequential access patterns.
Example
// StreamReader, StreamWriter, BinaryReader, BinaryWriter

using System.IO;
using System.Text;

string dir = Path.Combine(Path.GetTempPath(), "io_demo");
Directory.CreateDirectory(dir);

// --- StreamWriter / StreamReader ---
string csvPath = Path.Combine(dir, "data.csv");

await using var writer = new StreamWriter(csvPath, append: false, Encoding.UTF8);
await writer.WriteLineAsync("Id,Name,Score");
for (int i = 1; i <= 5; i++)
    await writer.WriteLineAsync($"{i},Student{i},{i * 18}");
// 'await using' calls DisposeAsync automatically

await using var reader = new StreamReader(csvPath, Encoding.UTF8);
string? header = await reader.ReadLineAsync();
Console.WriteLine($"Header: {header}");
while (await reader.ReadLineAsync() is { } row)
    Console.WriteLine($"  Row: {row}");

// --- BinaryWriter / BinaryReader ---
string binPath = Path.Combine(dir, "data.bin");

using (var bw = new BinaryWriter(File.OpenWrite(binPath)))
{
    bw.Write(42);           // int
    bw.Write(3.14);         // double
    bw.Write("hello");      // length-prefixed string
    bw.Write(true);         // bool
}

using (var br = new BinaryReader(File.OpenRead(binPath)))
{
    Console.WriteLine(br.ReadInt32());   // 42
    Console.WriteLine(br.ReadDouble());  // 3.14
    Console.WriteLine(br.ReadString()); // hello
    Console.WriteLine(br.ReadBoolean()); // True
}

Directory.Delete(dir, recursive: true);