10.1 Streams and Backing Stores

The stream is a fundamental abstraction used throughout the .NET Framework to model access to persistent data. A stream represents the flow of data coming in and out of a backing store. A backing store represents the endpoint of a stream. Although a backing store is often a file or network connection, in reality it can represent any medium capable of reading or writing raw data.

A simple example is to use a stream to read and write to a file on disk. However, streams and backing stores are not limited to disk and network I/O. A more sophisticated example is to use the cryptography support in the .NET Framework to encrypt or decrypt a stream of bytes as they move around in memory.

10.1.1 The Abstract Stream Class

Stream is an abstract class that defines operations for reading and writing a stream of raw typeless data as bytes. Once a stream is opened, it stays open and can be read from or written to until the stream is flushed and closed. Flushing a stream updates the writes made to the stream; closing a stream first flushes the stream, then closes the stream.

Stream has the methods CanRead, CanWrite, and CanSeek, for streams that support only sequential access. If a stream supports random access, the SetPosition method can move to a linear position on that stream.

The Stream class provides synchronous and asynchronous read and write operations. By default, an asynchronous method calls the stream's corresponding synchronous method by wrapping the synchronous method in a delegate type and starting a new thread. Similarly, by default, a synchronous method calls the stream's corresponding asynchronous method and waits until the thread has completed its operation. Classes that derive from Stream must override either the synchronous or asynchronous methods but may override both sets of methods if the need arises.

10.1.2 Concrete Stream-Derived Classes

The framework includes a number of different concrete implementations of the abstract base class Stream. Each implementation represents a different storage medium and allows a raw stream of bytes to be read from and written to the backing store.

Examples of this include the FileStream class (which reads and writes bytes to and from a file), the NetworkStream class (which sends and receives bytes over the network), and the stream returned from the static Stream.Null property (which serves as /dev/null for this platform).

The following example creates a text file on disk and uses the abstract File type to write data to it:

using System.IO;
class StreamFun {
  static void Main( ) {
    Stream s = new FileStream("foo.txt", FileMode.Create);
    s.Close( );

In addition, one stream may act as the frontend to another stream, performing additional processing on the underlying stream as needed. Examples of this include stream encryption/decryption and stream buffering.

The following is an example that converts the file output from the previous sample into its Base64 representation using the CryptoStream class:

using System;
using System.IO;
using System.Security.Cryptography;
class EncoderFun {
  static void Main( ) {
    Stream stm = new FileStream("foo.txt", FileMode.Open, FileAccess.Read);
    ICryptoTransform ict = new ToBase64Transform( );
    CryptoStream cs = new CryptoStream(stm, ict, CryptoStreamMode.Read);
    TextReader tr = new StreamReader(cs);
    string s = tr.ReadToEnd( );

    Part II: Programming with the .NET Framework
    Part IV: API Quick Reference