C # usando streams

116

Streams são meio misteriosos para mim. Não sei quando usar qual stream e como usá-los. Alguém pode me explicar como os streams são usados?

Se bem entendi, existem três tipos de fluxo:

  • stream
  • read stream
  • write stream

Isso está correto? E, por exemplo, qual é a diferença entre a Memorystreame a FileStream?

Martijn
fonte
13
você pode querer verificar stackoverflow.com/questions/507747/…
Preets de
3
Pegue um array de bytes e crie um wrapper para ele ( Stream) que expõe alguns métodos úteis, como leitura, escrita e mudança de posição. Agora você pode criar classes com base em seu armazenamento de apoio (FileStream, MemoryStream) que herdam Streame se baseiam nessa funcionalidade com base no armazenamento de apoio específico.
The Muffin Man

Respostas:

80

Um fluxo é um objeto usado para transferir dados. Há uma classe de fluxo genérica System.IO.Stream, da qual todas as outras classes de fluxo no .NET são derivadas. A Streamclasse lida com bytes.

As classes de fluxo concreto são usadas para lidar com outros tipos de dados além de bytes. Por exemplo:

  • A FileStreamclasse é usada quando a fonte externa é um arquivo
  • MemoryStream é usado para armazenar dados na memória
  • System.Net.Sockets.NetworkStream lida com dados de rede

Fluxos de leitor / gravador como StreamReadere StreamWriternão são fluxos - eles não são derivados System.IO.Stream, são projetados para ajudar a escrever e ler dados de e para fazer o streaming!

Arsen Mkrtchyan
fonte
3
Então, se bem entendi, o stream contém os dados e não faz nada com eles. As classes 'auxiliares' de leitor e gravador podem manipular (manipular) os dados no fluxo?
Martijn,
9
Não, Stream não é um contêiner de dados, ele é usado para transferir dados, por exemplo, FileStream transfere dados de byte [] para o arquivo físico, NetworkStream transfere byte [] por socket. As classes Reader Writer são classes auxiliares para escrever e ler do fluxo, por exemplo, StreamReader pode ser usado para ler string de fluxo e não byte []. se você fornecer FileStream como um parâmetro, ele lerá de File, se NetworkStream de socket.
Arsen Mkrtchyan
além disso, StreamReader e StreamWriter são para ler e gravar fluxos de TEXTO (caracteres).
1c1cle
1
tem um bom artigo para ajudá-lo a entender o MemoryStream. codeproject.com/Articles/832387/…
Jiaji Li
2
@ user420667. boa pergunta. Em ambos os casos AudioStream e TemperatureStream, eles provavelmente seriam BinaryStreams para o driver que está associado ao dispositivo. Ou você pode criar um CustomStream construído especificamente para a interface.
1c1cle
62

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.)

Tim Williams
fonte
As classes de adaptadores StreamWriter e Reader estão seriamente mal nomeadas. Obrigado por mencionar isso. Como é que eles inventaram esse nome ainda me surpreende.
Tarik,
Além disso, mesmo as classes de escritores e leitores binários são mal nomeadas.
Tarik
22

Os fluxos são bons para lidar com grandes quantidades de dados. Quando é impraticável carregar todos os dados na memória ao mesmo tempo, você pode abri-lo como um fluxo e trabalhar com pequenos pedaços dele.

carne
fonte
1
Adoraria ver um exemplo do que acabou de dizer "trabalhe com pequenos pedaços".
Jenna Leaf de
2
Os fluxos também são bons para pequenas quantidades de dados. Se um programador C # deseja manipular o conteúdo de um arquivo, ele deve usar streams, independentemente da quantidade de dados. A mesma afirmação também é verdadeira para fluxos de rede. Concedido, se o programador está codificando em uma linguagem de nível inferior como C, então é possível gravar chars ou bytes diretamente em um disco ou soquete, mas mesmo para uma pequena quantidade de dados, é demorado e mais propenso a erro.
1c1cle
10

Stream é apenas uma abstração (ou um invólucro) sobre um physicalstream de bytes. Este physicalfluxo é chamado de base stream. Portanto, sempre há um fluxo base sobre o qual um wrapper de fluxo é criado e, portanto, o wrapper é nomeado após o tipo de fluxo base FileStream, ou seja , MemoryStreametc.

A vantagem do wrapper de fluxo é que você obtém uma API unificada para interagir com fluxos de qualquer tipo subjacente, usb, fileetc.

Por que você trataria os dados como fluxo - porque os fragmentos de dados são carregados sob demanda, podemos inspecionar / processar os dados como fragmentos em vez de carregar os dados inteiros na memória. É assim que a maioria dos programas lida com arquivos grandes, por exemplo, para criptografar um arquivo de imagem do sistema operacional.

Anwar Husain
fonte
4

Existe apenas um tipo básico de Stream. No entanto, em várias circunstâncias, alguns membros lançarão uma exceção quando chamados porque, nesse contexto, a operação não estava disponível.

Por exemplo, a MemoryStreamé simplesmente uma maneira de mover bytes para dentro e para fora de um bloco de memória. Portanto, você pode chamar Read e Write nele.

Por outro lado, um FileStream permite que você leia ou escreva (ou ambos) de / para um arquivo. Se você pode realmente ler ou gravar depende de como o arquivo foi aberto. Você não pode gravar em um arquivo se você apenas o abriu para acesso de leitura.

AnthonyWJones
fonte
3

Eu começaria lendo sobre streams no MSDN: http://msdn.microsoft.com/en-us/library/system.io.stream.aspx

Memorystream e FileStream são streams usados ​​para trabalhar com memória bruta e arquivos respectivamente ...

Robban
fonte
Obrigado pelo link. Adorei "Você pode navegar pelo código-fonte online, baixar a referência para visualização offline e percorrer as fontes (incluindo patches e atualizações) durante a depuração". Esse recurso oferece um novo nível de percepção.
David
1

Eu não chamaria esses tipos diferentes de streams. A classe Stream possui as propriedades CanRead e CanWrite que informam se o fluxo específico pode ser lido e gravado.

A principal diferença entre diferentes classes de fluxo (como MemoryStream vs FileStream) é o armazenamento de apoio - de onde os dados são lidos ou onde são gravados. É meio óbvio pelo nome. Um MemoryStream armazena os dados apenas na memória, um FileStream é apoiado por um arquivo em disco, um NetworkStream lê os dados da rede e assim por diante.

Mattias S
fonte