7-day free trial — no payment today.

Streams in C#

Work with data as a flow of bytes using System.IO streams — reading and writing files, memory, network data, compression, and stream chaining.

What Is a Stream?

A stream is a sequence of bytes that flows from a source to a destination. Instead of loading an entire file or network response into memory at once, you read or write it piece by piece. This makes streams memory-efficient for large data. In C#, all streams inherit from the abstract base class `System.IO.Stream`, which defines a common interface: `Read()`, `Write()`, `Seek()`, `Position`, and `Length`.

1. Stream Concepts

Streams can be readable, writable, or both. They can support seeking (jumping to any position) or be forward-only. The base `Stream` class exposes all these capabilities.

FileStream — Reading & Writing Files

FileStream is the lowest-level file I/O class in C#. It gives you direct byte-level access to a file. For most text file work you will wrap it in a `StreamReader` or `StreamWriter`, but understanding FileStream is essential when you need binary I/O — images, audio, compressed data, or custom binary formats.

1. Writing and Reading with FileStream

Open a file with `FileStream`, write bytes to it, then read them back. Use `FileMode` to control whether the file is created, opened, or appended.

2. Reading Large Files in Chunks

Never load a huge file into a single byte array — read it in fixed-size chunks. This keeps memory usage constant regardless of file size.

StreamReader & StreamWriter

FileStream deals in raw bytes. `StreamReader` and `StreamWriter` wrap any stream and handle text encoding (UTF-8, ASCII, Unicode) for you. They are the go-to classes for reading and writing text files line by line.

1. Writing Text with StreamWriter

Wrap a FileStream in a StreamWriter to write strings instead of raw bytes. StreamWriter handles encoding and buffering automatically.

2. Reading Text with StreamReader

StreamReader reads text from any stream. Use `ReadLine()` for line-by-line processing and `ReadToEnd()` for small files.

MemoryStream & BufferedStream

MemoryStream acts like a file stream but lives entirely in RAM — perfect for building up byte sequences, intermediate processing, or unit-testing stream code. BufferedStream wraps any stream and adds an internal buffer so that many small reads/writes are batched into larger, more efficient I/O operations.

1. MemoryStream — In-Memory Buffer

Build byte content in memory, then use it as a stream — no temporary files needed. Commonly used for image processing, serialisation, and HTTP response bodies.

2. BufferedStream — Faster I/O

Wrap a slow stream (like a FileStream or NetworkStream) in a BufferedStream to batch many small reads/writes into fewer, larger OS calls.

Compression Streams

C# provides compression streams in `System.IO.Compression`. You chain them over another stream: data passes through the compressor/decompressor as it flows. `GZipStream` produces `.gz` files; `DeflateStream` produces raw DEFLATE data (used inside ZIP and HTTP `Content-Encoding: deflate`). Both are wrappers — they do not store data themselves.

1. Compress & Decompress with GZipStream

Pipe data through GZipStream to compress it to disk. Reverse the pipe to decompress. Works with any text or binary data.

Async Streams

Blocking a thread while waiting for disk or network I/O wastes resources. C# stream classes expose async counterparts — `ReadAsync()`, `WriteAsync()`, `CopyToAsync()` — that release the thread while waiting. For producing sequences of data asynchronously, C# 8 introduced `IAsyncEnumerable<T>` with `await foreach`.

1. Async File Read & Write

Use `await ReadAsync` and `await WriteAsync` to perform file I/O without blocking the calling thread. Always use `FileOptions.Asynchronous` when creating a FileStream for async use.

2. IAsyncEnumerable — Async Streams

Produce items one at a time asynchronously with `yield return` inside an `async` method, and consume them with `await foreach`.