Você pode explicar o conceito de fluxos?

186

Eu entendo que um fluxo é uma representação de uma sequência de bytes. Cada fluxo fornece meios para ler e gravar bytes em seu armazenamento de backup fornecido. Mas qual é o sentido do fluxo? Por que a loja de apoio em si não é a que interagimos?

Por alguma razão, esse conceito simplesmente não está clicando para mim. Eu li vários artigos, mas acho que preciso de uma analogia ou algo assim.

Rob Sobers
fonte

Respostas:

234

A palavra "fluxo" foi escolhida porque representa (na vida real) um significado muito semelhante ao que queremos transmitir quando o usamos.

Vamos esquecer um pouco a loja de apoio e começar a pensar na analogia de um fluxo de água. Você recebe um fluxo contínuo de dados, assim como a água flui continuamente em um rio. Você não sabe necessariamente de onde vêm os dados e, na maioria das vezes, não precisa; seja de um arquivo, soquete ou qualquer outra fonte, não importa (não deveria) realmente. Isso é muito semelhante ao recebimento de um fluxo de água, pelo qual você não precisa saber de onde ele vem; seja de um lago, de uma fonte ou de qualquer outra fonte, não importa (não deveria) realmente.

Dito isto, uma vez que você começa a pensar que só se preocupa em obter os dados necessários, independentemente de onde eles vêm, as abstrações que as outras pessoas mencionaram se tornam mais claras. Você começa a pensar que pode agrupar fluxos e seus métodos ainda funcionarão perfeitamente. Por exemplo, você pode fazer isso:

int ReadInt(StreamReader reader) { return Int32.Parse(reader.ReadLine()); }

// in another method:
Stream fileStream = new FileStream("My Data.dat");
Stream zipStream = new ZipDecompressorStream(fileStream);
Stream decryptedStream = new DecryptionStream(zipStream);
StreamReader reader = new StreamReader(decryptedStream);

int x = ReadInt(reader);

Como você vê, fica muito fácil alterar sua fonte de entrada sem alterar sua lógica de processamento. Por exemplo, para ler seus dados de um soquete de rede em vez de um arquivo:

Stream stream = new NetworkStream(mySocket);
StreamReader reader = new StreamReader(stream);
int x = ReadInt(reader);

Tão fácil quanto possível. E a beleza continua, pois você pode usar qualquer tipo de fonte de entrada, desde que seja possível criar um "wrapper" de fluxo para ela. Você pode até fazer isso:

public class RandomNumbersStreamReader : StreamReader {
    private Random random = new Random();

    public String ReadLine() { return random.Next().ToString(); }
}

// and to call it:
int x = ReadInt(new RandomNumbersStreamReader());

Vejo? Desde que o seu método não se importe com a fonte de entrada, você pode personalizá-la de várias maneiras. A abstração permite dissociar a entrada da lógica de processamento de uma maneira muito elegante.

Observe que o fluxo que criamos a nós mesmos não tem uma loja de apoio, mas ainda serve perfeitamente a nossos propósitos.

Então, para resumir, um fluxo é apenas uma fonte de entrada, escondendo (abstraindo) outra fonte. Contanto que você não quebre a abstração, seu código será muito flexível.

Hosam Aly
fonte
6
O pensamento abstrato (e a explicação) parece estar no seu sangue;) Sua analogia com a água (e, portanto, referências metafóricas) me lembrou Omar Khayyam.
Java.is.for.desktop 27/03
@ HosamAly Sua explicação é muito clara, mas algo me confunde um pouco no código de exemplo. A conversão explícita de string para int é feita automaticamente, fazendo ReadInt? Eu acredito que eu poderia fazer ReadString também?
Rushino 26/10/12
1
@Rushino Não há conversões no código acima. O método ReadInté definido no topo int.Parse, usando , que recebe a string retornada reader.ReadLine()e a analisa. Claro que você pode criar um ReadStringmétodo semelhante . Isso é claro o suficiente?
Hosam Aly
Bem colocado. Os fluxos para mim são as abstrações genéricas mais simples e poderosas em toda a programação. Ter o .net basic Stream.Copytorna a vida muito mais fácil em muitos aplicativos.
Felype 5/09/17
38

O ponto é que você não precisa saber qual é a loja de suporte - é uma abstração sobre ela. De fato, pode até não haver uma loja de apoio - você pode estar lendo a partir de uma rede e os dados nunca são "armazenados".

Se você pode escrever um código que funcione, esteja você falando com um sistema de arquivos, memória, rede ou qualquer outra coisa que suporte a ideia de fluxo, seu código é muito mais flexível.

Além disso, os fluxos geralmente são encadeados - você pode ter um fluxo que comprime o que quer que seja colocado nele, gravando o formulário compactado em outro fluxo ou criptografando os dados, etc. descriptografar, descomprimir ou qualquer outra coisa.

Jon Skeet
fonte
Os diferentes tipos de leitores de fluxo usados ​​no exemplo @HosamAly acima não implicam que você saiba qual é a loja de suporte? Acho que FileStream, NetworkStream etc ... estão lendo esses tipos de fontes. Além disso, existem casos em que você não sabe qual pode ser o armazenamento de backup e que seria escolhido dinamicamente enquanto o programa é executado? Eu pessoalmente não me deparei com isso e gostaria de saber mais.
user137717
Além disso, os fluxos podem canalizar dados através de algum processo à medida que os dados são gerados ou preciso acessar o conjunto de dados completo em que quero operar quando inicio o processo?
user137717
@ user137717: Não, se você fizer um StreamReader- ou melhor, a TextReader, seu código não saberá que tipo de fluxo está subjacente ao fluxo de dados. Ou melhor, ele pode usar a BaseStreampropriedade para descobrir o tipo - mas pode ser um tipo que seu código nunca viu antes. O ponto é que você não deveria se importar. E sim, você pode absolutamente escrever código que às vezes será usado para um fluxo de rede e, às vezes, para um fluxo de arquivos. Quanto aos fluxos de dados de tubulação através de um processo - bem, isso não seria feito dentro do processo ... seria o provedor do fluxo.
22815 Jon Skeet
30

O objetivo do fluxo é fornecer uma camada de abstração entre você e o armazenamento de suporte. Portanto, um determinado bloco de código que usa um fluxo não precisa se importar se o armazenamento de backup é um arquivo de disco, memória, etc ...

Torlack
fonte
Sim, permite trocar o tipo de fluxo sem quebrar seu código. Por exemplo, você pode ler um arquivo em uma chamada e, em seguida, um buffer de memória na próxima.
Craig
Eu acrescentaria que o motivo pelo qual você gostaria de fazer isso é que muitas vezes você não precisa da capacidade de busca de arquivos ao ler ou gravar um arquivo e, portanto, se você usa um fluxo, esse mesmo código pode ser facilmente usado para ler ou gravar em um soquete de rede, por exemplo.
Alxp 03/02/09
11

Não é sobre riachos - é sobre nadar. Se você pode nadar em um stream, então você pode nadar em qualquer stream que encontrar.

dmajkic
fonte
7

Para adicionar à câmara de eco, o fluxo é uma abstração, para que você não se importe com o armazenamento subjacente. Faz mais sentido quando você considera cenários com e sem fluxos.

Os arquivos são desinteressantes, na maioria das vezes, porque os fluxos não fazem muito acima e além dos métodos não baseados em fluxo com os quais estou familiarizado. Vamos começar com arquivos da Internet.

Se eu quiser baixar um arquivo da Internet, tenho que abrir um soquete TCP, fazer uma conexão e receber bytes até que não haja mais bytes. Eu tenho que gerenciar um buffer, saber o tamanho do arquivo esperado e escrever código para detectar quando a conexão é interrompida e lidar com isso adequadamente.

Digamos que eu tenho algum tipo de objeto TcpDataStream. Eu o crio com as informações de conexão apropriadas e leio os bytes do fluxo até que ele diga que não há mais bytes. O fluxo lida com o gerenciamento de buffer, as condições de final de dados e o gerenciamento de conexões.

Dessa maneira, os fluxos facilitam a E / S. Você certamente poderia escrever uma classe TcpFileDownloader que faz o que o fluxo faz, mas então você tem uma classe específica para o TCP. A maioria das interfaces de fluxo simplesmente fornece um método Read () e Write (), e quaisquer conceitos mais complicados são tratados pela implementação interna. Por esse motivo, você pode usar o mesmo código básico para ler ou gravar na memória, arquivos de disco, soquetes e muitos outros armazenamentos de dados.

OwenP
fonte
5

A visualização que uso são correias transportadoras, não em fábricas reais porque não sei nada sobre isso, mas em fábricas de cartum em que os itens se movem ao longo das linhas e são carimbados, encaixotados, contados e verificados por uma sequência de dispositivos burros.

Você tem componentes simples que fazem uma coisa, por exemplo, um dispositivo para colocar uma cereja em um bolo. Este dispositivo possui um fluxo de entrada de bolos sem cereja e um fluxo de saída de bolos com cerejas. Vale a pena mencionar três vantagens em estruturar seu processamento dessa maneira.

Em primeiro lugar, ele simplifica os componentes: se você deseja colocar cobertura de chocolate em um bolo, não precisa de um dispositivo complicado que saiba tudo sobre bolos, pode criar um dispositivo idiota que cola a cobertura de chocolate no que quer que seja alimentado ( os desenhos animados, isso chega ao ponto de não saber que o próximo item não é um bolo, é Wile E. Coyote).

Em segundo lugar, você pode criar produtos diferentes colocando os dispositivos em diferentes seqüências: talvez você queira que seus bolos tenham cobertura em cima da cereja em vez de cereja em cima da cobertura, e você pode fazer isso simplesmente trocando os dispositivos pela linha .

Em terceiro lugar, os dispositivos não precisam gerenciar inventário, boxe ou unboxing. A maneira mais eficiente de agregar e empacotar as coisas é mutável: talvez hoje você esteja colocando seus bolos em caixas de 48 e enviando-os pelo caminhão, mas amanhã você deseja enviar caixas de seis em resposta a pedidos personalizados. Esse tipo de alteração pode ser acomodado substituindo ou reconfigurando as máquinas no início e no final da linha de produção; a máquina cerejeira no meio da linha não precisa ser alterada para processar um número diferente de itens de cada vez, sempre trabalha com um item de cada vez e não precisa saber como é sua entrada ou saída. sendo agrupado.


fonte
Ótimo exemplo de analogia como explicação.
22617 Richfield Thomas
5

Quando ouvi falar sobre streaming pela primeira vez, foi no contexto de transmissão ao vivo com uma webcam. Portanto, um host está transmitindo conteúdo de vídeo e o outro host está recebendo o conteúdo de vídeo. Então, isso está fluindo? Bem ... sim ... mas uma transmissão ao vivo é um conceito concreto, e acho que a pergunta se refere ao conceito abstrato de Streaming. Veja https://en.wikipedia.org/wiki/Live_streaming

Então vamos seguir em frente.


O vídeo não é o único recurso que pode ser transmitido. O áudio também pode ser transmitido. Então, agora estamos falando sobre streaming de mídia. Veja https://en.wikipedia.org/wiki/Streaming_media . O áudio pode ser entregue da fonte ao destino de várias maneiras. Então, vamos comparar alguns métodos de entrega de dados entre si.

Download de arquivo clássico O download de arquivo clássico não acontece em tempo real. Antes de usar o arquivo, você deverá aguardar a conclusão do download.

Download progressivo Os blocos de download progressivo baixam dados do arquivo de mídia transmitido para um buffer temporário. Os dados nesse buffer são viáveis: os dados de áudio e vídeo no buffer são reproduzíveis. Por esse motivo, os usuários podem assistir / ouvir o arquivo de mídia transmitido durante o download. É possível avançar e retroceder rapidamente, fora do curso dentro do buffer. De qualquer forma, o download progressivo não é uma transmissão ao vivo.

Streaming Acontece em tempo real e agrupa dados. O streaming é implementado em transmissões ao vivo. Os clientes que estão ouvindo a transmissão não podem avançar ou retroceder rapidamente. Nos fluxos de vídeo, os dados são descartados após a reprodução.

Um servidor de streaming mantém uma conexão bidirecional com seu cliente, enquanto um servidor da Web fecha a conexão após uma resposta do servidor.


Áudio e vídeo não são a única coisa que pode ser transmitida. Vamos dar uma olhada no conceito de fluxos no manual do PHP.

um fluxo é um objeto de recurso que exibe um comportamento flexível. Ou seja, ele pode ser lido ou gravado de maneira linear e pode ser capaz de buscar () em um local arbitrário no fluxo. Link: https://www.php.net/manual/en/intro.stream.php

No PHP, um recurso é uma referência a uma fonte externa, como um arquivo, conexão com o banco de dados. Portanto, em outras palavras, um fluxo é uma fonte que pode ser lida ou gravada. Então, se você trabalhou com fopen(), então você já trabalhou com fluxos.

Um exemplo de um arquivo de texto que está sujeito a streaming:

// Let's say that cheese.txt is a file that contains this content: 
// I like cheese, a lot! My favorite cheese brand is Leerdammer.
$fp = fopen('cheese.txt', 'r');

$str8 = fread($fp, 8); // read first 8 characters from stream. 

fseek($fp, 21); // set position indicator from stream at the 21th position (0 = first position)
$str30 = fread($fp, 30); // read 30 characters from stream

echo $str8; // Output: I like c 
echo $str30; // Output: My favorite cheese brand is L

Arquivos zip também podem ser transmitidos. Além disso, o streaming não se limita a arquivos. As conexões HTTP, FTP, SSH e Entrada / Saída também podem ser transmitidas.


O que a wikipedia diz sobre o conceito de Streaming?

Na ciência da computação, um fluxo é uma sequência de elementos de dados disponibilizados ao longo do tempo. Um fluxo pode ser considerado como itens em uma correia transportadora sendo processados ​​um de cada vez, e não em grandes lotes.

Veja: https://en.wikipedia.org/wiki/Stream_%28computing%29 .

Os links da Wikipedia para isso: https://srfi.schemers.org/srfi-41/srfi-41.html e os escritores têm isso a dizer sobre fluxos:

Os fluxos, às vezes chamados de listas preguiçosas, são uma estrutura de dados seqüencial contendo elementos computados somente sob demanda. Um fluxo é nulo ou é um par com um fluxo em seu cdr. Como os elementos de um fluxo são computados apenas quando acessados, os fluxos podem ser infinitos.

Portanto, um fluxo é realmente uma estrutura de dados.


Minha conclusão: um fluxo é uma fonte que pode conter dados que podem ser lidos ou gravados de maneira seqüencial. Um fluxo não lê tudo o que a fonte contém de uma só vez, lê / grava sequencialmente.


Links úteis:

  1. http://www.slideshare.net/auroraeosrose/writing-and-using-php-streams-and-sockets-zendcon-2011 Fornece uma apresentação muito clara
  2. https://www.sk89q.com/2010/04/introduction-to-php-streams/
  3. http://www.netlingo.com/word/stream-or-streaming.php
  4. http://www.brainbell.com/tutorials/php/Using_PHP_Streams.htm
  5. http://www.sitepoint.com/php-streaming-output-buffering-explained/
  6. http://php.net/manual/en/wrappers.php
  7. http://www.digidata-lb.com/streaming/Streaming_Proposal.pdf
  8. http://www.webopedia.com/TERM/S/streaming.html
  9. https://en.wikipedia.org/wiki/Stream_%28computing%29
  10. https://srfi.schemers.org/srfi-41/srfi-41.html
Julian
fonte
4

É apenas um conceito, outro nível de abstração que facilita sua vida. E todos eles têm uma interface comum, o que significa que você pode combiná-los de maneira semelhante a um tubo. Por exemplo, codifique para base64, feche e grave-o no disco e tudo em uma linha!

vava
fonte
Isso é útil, certamente, mas eu não diria que esse é o "ponto inteiro". Mesmo sem encadeamento, é útil ter uma abstração comum.
911 Jon Skeet
Sim você está certo. Eu mudei as palavras para deixar isso claro.
vava
Sim, isso é melhor. Espero que você não tenha pensado que eu estava sendo muito exigente!
911 Jon Skeet
3

A melhor explicação dos fluxos que eu vi é o capítulo 3 do SICP . (Você pode precisar ler os 2 primeiros capítulos para que faça sentido, mas você deve fazer assim mesmo. :-)

Eles não usam sterams para bytes, mas números inteiros. Os grandes pontos que obtive dele foram:

  • Fluxos são listas atrasadas
  • A sobrecarga computacional [de avidamente computar tudo antes do tempo, em alguns casos] é ultrajante
  • Podemos usar fluxos para representar sequências infinitamente longas
Ken
fonte
Atualmente, estou atualmente no capítulo 1 do SICP. Obrigado!
Rob Sobers
2
alguém gostaria de dizer ao SICP o fluxo de outros. uma característica importante do fluxo SICP é a preguiça , enquanto o conceito genérico de fluxo enfatiza a abstração nas seqüências de dados .
象嘉道
2

Outro ponto (para ler a situação do arquivo):

  1. streampode permitir que você faça outra coisa antes finished reading all content of the file.
  2. você pode economizar memória, porque não precisa carregar todo o conteúdo do arquivo de uma só vez.
vikyd
fonte
1

Pense nos fluxos como uma fonte abstrata de dados (bytes, caracteres, etc.). Eles abstraem a mecânica real de leitura e gravação na fonte de dados concreta, seja um soquete de rede, arquivo em um disco ou uma resposta do servidor da web.

Anton Gogolev
fonte
1

Eu acho que você precisa considerar que a própria loja de backup geralmente é apenas outra abstração. Um fluxo de memória é muito fácil de entender, mas um arquivo é radicalmente diferente dependendo do sistema de arquivos que você está usando, independentemente do disco rígido que está usando. Na verdade, nem todos os fluxos ficam no topo de uma loja de backup: os fluxos de rede praticamente são apenas fluxos.

O ponto de um fluxo é que restringimos nossa atenção ao que é importante. Por ter uma abstração padrão, podemos executar operações comuns. Mesmo que você não queira, por exemplo, pesquisar um arquivo ou uma resposta HTTP para URLs hoje, não significa que não desejará amanhã.

Os fluxos foram originalmente concebidos quando a memória era pequena se comparada ao armazenamento. Apenas ler um arquivo C pode ser uma carga significativa. Minimizar a pegada de memória foi extremamente importante. Portanto, uma abstração na qual muito pouco precisava ser carregado foi muito útil. Hoje, é igualmente útil ao executar comunicação em rede e, ao que parece, raramente é restritivo quando lidamos com arquivos. A capacidade de adicionar transparentemente itens como buffer de maneira geral o torna ainda mais útil.

Julian Birch
fonte
0

Um fluxo é um resumo de uma sequência de bytes. A idéia é que você não precisa saber de onde vêm os bytes, apenas que você pode lê-los de maneira padronizada.

Por exemplo, se você processar dados por meio de um fluxo, não importará para o seu código se os dados vierem de um arquivo, uma conexão de rede, uma string, um blob em um banco de dados, etc, etc.

Não há nada de errado em interagir com a loja de backup em si, exceto pelo fato de vincular você à implementação da loja de backup.

Sean
fonte
0

Um fluxo é uma abstração que fornece um conjunto padrão de métodos e propriedades para interagir com dados. Ao abstrair da mídia de armazenamento real, seu código pode ser gravado sem total confiança no que é essa mídia ou mesmo na implementação dessa mídia.

Uma boa analogia pode ser considerar uma bolsa. Você não se importa com o que é feito ou o que uma bolsa faz quando coloca suas coisas nela, desde que a bolsa realize o trabalho de ser uma bolsa e você possa recuperá-las. Um fluxo define para a mídia de armazenamento o que o conceito de bolsa define para diferentes instâncias de uma bolsa (como bolsa de lixo, bolsa, mochila etc.) - as regras de interação.

Jeff Yates
fonte
0

Vou ser breve, eu estava perdendo a palavra aqui:

Os fluxos são filas geralmente armazenadas no buffer que contém qualquer tipo de dados.

(Agora, como todos sabemos o que são filas, não há necessidade de explicar isso mais.)

Marcus
fonte