Para expandir um pouco as outras respostas aqui, e ajudar a explicar muito do código de exemplo que você verá espalhado, na maioria das vezes você não lê e grava em um fluxo diretamente. Streams são um meio de baixo nível para transferir dados.
Você notará que as funções de leitura e escrita são todas orientadas por bytes, por exemplo, WriteByte (). Não há funções para lidar com inteiros, strings etc. Isso torna o fluxo de uso muito geral, mas menos simples de trabalhar se, digamos, você quiser apenas transferir texto.
No entanto, o .NET fornece classes que convertem entre tipos nativos e a interface de fluxo de baixo nível e transfere os dados de ou para o fluxo para você. Algumas dessas classes notáveis são:
StreamWriter // Badly named. Should be TextWriter.
StreamReader // Badly named. Should be TextReader.
BinaryWriter
BinaryReader
Para usá-los, primeiro você adquire seu fluxo, depois cria uma das classes acima e a associa ao fluxo. Por exemplo
MemoryStream memoryStream = new MemoryStream();
StreamWriter myStreamWriter = new StreamWriter(memoryStream);
StreamReader e StreamWriter convertem entre tipos nativos e suas representações de string e então transferem as strings de e para o fluxo como bytes. assim
myStreamWriter.Write(123);
irá escrever "123" (três caracteres '1', '2' e depois '3') no stream. Se você estiver lidando com arquivos de texto (por exemplo, html), StreamReader e StreamWriter são as classes que você usaria.
Enquanto que
myBinaryWriter.Write(123);
gravará quatro bytes que representam o valor inteiro de 32 bits 123 (0x7B, 0x00, 0x00, 0x00). Se você estiver lidando com arquivos binários ou protocolos de rede, BinaryReader e BinaryWriter são o que você pode usar. (Se estiver trocando dados com redes ou outros sistemas, você precisa estar atento ao endianness , mas isso é outro post.)