Pouvez-vous expliquer le concept de flux?

186

Je comprends qu'un flux est une représentation d'une séquence d'octets. Chaque flux fournit des moyens pour lire et écrire des octets dans son magasin de stockage donné. Mais quel est le but du flux? Pourquoi le backing store lui-même n'est-il pas ce avec quoi nous interagissons?

Pour une raison quelconque, ce concept ne clique pas pour moi. J'ai lu un tas d'articles, mais je pense que j'ai besoin d'une analogie ou quelque chose.

Rob Sobers
la source

Réponses:

234

Le mot «flux» a été choisi car il représente (dans la vraie vie) un sens très similaire à ce que nous voulons transmettre lorsque nous l'utilisons.

Oublions un peu le magasin de support et commençons à penser à l'analogie avec un courant d'eau. Vous recevez un flux continu de données, tout comme l'eau coule en permanence dans une rivière. Vous ne savez pas nécessairement d'où proviennent les données, et le plus souvent vous n'en avez pas besoin; que ce soit à partir d'un fichier, d'une socket ou de toute autre source, cela n'a pas (ne devrait pas) vraiment avoir d'importance. C'est très similaire à recevoir un jet d'eau, où vous n'avez pas besoin de savoir d'où il vient; que ce soit d'un lac, d'une fontaine ou de toute autre source, cela n'a pas (ne devrait pas) vraiment avoir d'importance.

Cela dit, une fois que vous commencez à penser que vous ne vous souciez que d'obtenir les données dont vous avez besoin, quelle que soit leur origine, les abstractions dont d'autres personnes ont parlé deviennent plus claires. Vous commencez à penser que vous pouvez envelopper les flux et que vos méthodes fonctionneront toujours parfaitement. Par exemple, vous pouvez faire ceci:

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

Comme vous le voyez, il devient très facile de changer votre source d'entrée sans changer votre logique de traitement. Par exemple, pour lire vos données à partir d'une socket réseau au lieu d'un fichier:

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

Aussi simple que possible. Et la beauté continue, car vous pouvez utiliser n'importe quel type de source d'entrée, tant que vous pouvez créer un flux "wrapper" pour cela. Vous pouvez même faire ceci:

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());

Voir? Tant que votre méthode ne se soucie pas de la source d'entrée, vous pouvez personnaliser votre source de différentes manières. L'abstraction vous permet de découpler l'entrée de la logique de traitement d'une manière très élégante.

Notez que le flux que nous avons créé nous-mêmes n'a pas de magasin de support, mais il répond parfaitement à nos besoins.

Donc, pour résumer, un flux n'est qu'une source d'entrée, cachant (abstraite) une autre source. Tant que vous ne brisez pas l'abstraction, votre code sera très flexible.

Hosam Aly
la source
6
La pensée abstraite (et l'explication) semble être dans votre sang;) Votre analogie avec l'eau (et donc les références métaphoriques) m'a rappelé Omar Khayyam.
java.is.for.desktop
@HosamAly Votre explication est très claire mais quelque chose me déroute un peu dans l'exemple de code. La conversion explicite de string en int se fait automatiquement en faisant ReadInt? je crois que je pourrais aussi faire ReadString?
Rushino
1
@Rushino Il n'y a aucune conversion dans le code ci-dessus. La méthode ReadIntest définie tout en haut à l'aide de int.Parse, qui reçoit la chaîne renvoyée reader.ReadLine()et l'analyse. Bien sûr, vous pouvez créer une ReadStringméthode similaire . Est-ce assez clair?
Hosam Aly
Bien placé. Les flux sont pour moi les abstractions génériques les plus simples et les plus puissantes de l'ensemble de la programmation. Avoir .net basic Stream.Copyrend la vie tellement plus facile dans de nombreuses applications.
Felype
38

Le fait est que vous ne devriez pas avoir à savoir ce qu'est le magasin de support - c'est une abstraction dessus. En effet, il pourrait même ne pas y avoir magasin de sauvegarde - vous pourriez lire à partir d'un réseau et les données ne sont jamais «stockées» du tout.

Si vous pouvez écrire du code qui fonctionne, que vous parliez à un système de fichiers, à la mémoire, à un réseau ou à tout autre élément prenant en charge l'idée de flux, votre code est beaucoup plus flexible.

De plus, les flux sont souvent enchaînés - vous pouvez avoir un flux qui compresse tout ce qui y est mis, en écrivant le formulaire compressé sur un autre flux, ou un qui crypte les données, etc. À l'autre extrémité, il y aurait l'inverse chaîne, décryptage, décompression ou autre.

Jon Skeet
la source
Les différents types de lecteurs de flux utilisés dans l'exemple @HosamAly ci-dessus n'impliquent-ils pas que vous savez ce qu'est le magasin de support? Je suppose que FileStream, NetworkStream etc ... lisent à partir de ces types de sources. De plus, y a-t-il des cas où vous ne savez pas ce que pourrait être le magasin de stockage et qui serait choisi de manière dynamique pendant l'exécution du programme? Je n'ai tout simplement pas rencontré cela personnellement et j'aimerais en savoir plus.
user137717
En outre, les flux de données peuvent-ils passer par un processus au fur et à mesure que les données sont générées ou ai-je besoin d'accéder à l'ensemble de données complet sur lequel je souhaite opérer lorsque je commence le processus?
user137717
@ user137717: Non, si vous prenez juste un StreamReader- ou mieux, un TextReaderalors votre code ne sait pas quel type de flux sous-tend le flux de données. Ou plutôt, il peut utiliser la BaseStreampropriété pour trouver le type - mais il peut s'agir d'un type que votre code n'a jamais vu auparavant. Le fait est que vous ne devriez pas vous en soucier. Et oui, vous pouvez absolument finir par écrire du code qui sera parfois utilisé pour un flux réseau et parfois utilisé pour un flux de fichiers. En ce qui concerne les flux qui acheminent des données à travers un processus - eh bien, cela ne serait pas fait à l' intérieur du processus ... ce serait le fournisseur de flux.
Jon Skeet
30

Le but du flux est de fournir une couche d'abstraction entre vous et le magasin de support. Ainsi, un bloc de code donné qui utilise un flux n'a pas besoin de se soucier si le magasin de sauvegarde est un fichier disque, une mémoire, etc.

Torlack
la source
Oui, cela vous permet d'échanger le type de flux sans casser votre code. Par exemple, vous pouvez lire un fichier lors d'un appel, puis une mémoire tampon sur le suivant.
Craig le
J'ajouterais que la raison pour laquelle vous voudriez faire cela est que souvent vous n'avez pas besoin de la capacité de recherche de fichier lors de la lecture ou de l'écriture d'un fichier, et donc si vous utilisez un flux, ce même code peut facilement être utilisé pour lire ou écrire dans une prise réseau, par exemple.
alxp
11

Il ne s'agit pas de ruisseaux, mais de natation. Si vous pouvez nager un ruisseau, vous pouvez nager n'importe quel ruisseau que vous rencontrez.

dmajkic
la source
7

Pour ajouter à la chambre d'écho, le flux est une abstraction donc vous ne vous souciez pas du magasin sous-jacent. Cela a plus de sens lorsque vous considérez des scénarios avec et sans flux.

Les fichiers sont pour la plupart inintéressants car les flux ne font pas grand-chose au-delà de ce que les méthodes non basées sur les flux que je connais. Commençons par les fichiers Internet.

Si je veux télécharger un fichier depuis Internet, je dois ouvrir une socket TCP, établir une connexion et recevoir des octets jusqu'à ce qu'il n'y ait plus d'octets. Je dois gérer un tampon, connaître la taille du fichier attendu et écrire du code pour détecter le moment où la connexion est interrompue et gérer cela de manière appropriée.

Disons que j'ai une sorte d'objet TcpDataStream. Je le crée avec les informations de connexion appropriées, puis je lis les octets du flux jusqu'à ce qu'il dise qu'il n'y a plus d'octets. Le flux gère la gestion de la mémoire tampon, les conditions de fin de données et la gestion de connexion.

De cette manière, les flux facilitent les E / S. Vous pouvez certainement écrire une classe TcpFileDownloader qui fait ce que fait le flux, mais vous avez alors une classe spécifique à TCP. La plupart des interfaces de flux fournissent simplement une méthode Read () et Write (), et tous les concepts plus compliqués sont gérés par l'implémentation interne. Pour cette raison, vous pouvez utiliser le même code de base pour lire ou écrire dans la mémoire, les fichiers disque, les sockets et de nombreux autres magasins de données.

OwenP
la source
5

La visualisation que j'utilise est des bandes transporteuses, pas dans de vraies usines parce que je ne sais rien à ce sujet, mais dans des usines de dessins animés où les articles se déplacent le long des lignes et sont estampés et emballés, comptés et vérifiés par une séquence de dispositifs stupides.

Vous avez des composants simples qui font une chose, par exemple un appareil pour mettre une cerise sur le gâteau. Cet appareil a un flux d'entrée de gâteaux sans cerises et un flux de sortie de gâteaux aux cerises. Il y a trois avantages à mentionner en structurant votre traitement de cette manière.

Tout d'abord, cela simplifie les composants eux-mêmes: si vous voulez mettre du glaçage au chocolat sur un gâteau, vous n'avez pas besoin d'un appareil compliqué qui sait tout sur les gâteaux, vous pouvez créer un appareil stupide qui colle le glaçage au chocolat sur tout ce qui y est introduit (en les dessins animés, cela va jusqu'à ne pas savoir que l'élément suivant n'est pas un gâteau, c'est Wile E. Coyote).

Deuxièmement, vous pouvez créer différents produits en mettant les appareils dans différentes séquences: peut-être voulez-vous que vos gâteaux aient du glaçage sur la cerise au lieu de la cerise sur le glaçage, et vous pouvez le faire simplement en échangeant les appareils sur la ligne .

Troisièmement, les appareils n'ont pas besoin de gérer l'inventaire, la mise en boîte ou le déballage. Le moyen le plus efficace d'agréger et de conditionner les choses est variable: peut-être qu'aujourd'hui vous mettez vos gâteaux dans des boîtes de 48 et les expédiez par camion, mais demain vous voulez envoyer des boîtes de six en réponse à des commandes personnalisées. Ce type de changement peut être adapté en remplaçant ou en reconfigurant les machines au début et à la fin de la ligne de production; la machine à cerises au milieu de la ligne n'a pas besoin d'être modifiée pour traiter un nombre différent d'éléments à la fois, elle fonctionne toujours avec un élément à la fois et elle n'a pas besoin de savoir comment est son entrée ou sa sortie étant groupé.


la source
Excellent exemple d'analogie comme explication.
Richie Thomas
5

Quand j'ai entendu parler du streaming pour la première fois, c'était dans le cadre du streaming en direct avec une webcam. Ainsi, un hôte diffuse du contenu vidéo et l'autre hôte reçoit le contenu vidéo. Alors, est-ce que ce streaming? Eh bien ... oui ... mais un flux en direct est un concept concret, et je pense que la question se réfère au concept abstrait de Streaming. Voir https://en.wikipedia.org/wiki/Live_streaming

Alors passons à autre chose.


La vidéo n'est pas la seule ressource qui peut être diffusée. L'audio peut également être diffusé. Nous parlons donc maintenant de médias en streaming. Voir https://en.wikipedia.org/wiki/Streaming_media . L'audio peut être transmis de la source à la cible de nombreuses manières. Comparons donc certaines méthodes de livraison de données les unes aux autres.

Téléchargement de fichiers classiques Le téléchargement de fichiers classiques ne se fait pas en temps réel. Avant de prendre le fichier à utiliser, vous devrez attendre la fin du téléchargement.

Téléchargement progressif Les blocs de téléchargement progressif téléchargent les données du fichier multimédia diffusé vers une mémoire tampon temporaire. Les données de ce tampon sont exploitables: les données audio-vidéo du tampon sont lisibles. Pour cette raison, les utilisateurs peuvent regarder / écouter le fichier multimédia diffusé pendant le téléchargement. Une avance rapide et un retour rapide sont possibles, hors de la mémoire tampon. Quoi qu'il en soit, le téléchargement progressif n'est pas une diffusion en direct.

Le streaming se produit en temps réel et segmente les données. Le streaming est implémenté dans les diffusions en direct. Les clients qui écoutent la diffusion ne peuvent pas avancer ou reculer rapidement. Dans les flux vidéo, les données sont supprimées après la lecture.

Un serveur de streaming conserve une connexion bidirectionnelle avec son client, tandis qu'un serveur Web ferme la connexion après une réponse du serveur.


L'audio et la vidéo ne sont pas les seuls à pouvoir être diffusés. Jetons un œil au concept de flux dans le manuel PHP.

un flux est un objet ressource qui présente un comportement diffusable. Autrement dit, il peut être lu ou écrit de manière linéaire, et peut être capable de fseek () vers un emplacement arbitraire dans le flux. Lien: https://www.php.net/manual/en/intro.stream.php

En PHP, une ressource est une référence à une source externe comme un fichier, une connexion à une base de données. En d'autres termes, un flux est une source qui peut être lue ou écrite. Donc, si vous avez travaillé avec fopen(), vous avez déjà travaillé avec des flux.

Un exemple de fichier texte soumis au 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

Les fichiers Zip peuvent également être diffusés. De plus, le streaming ne se limite pas aux fichiers. Les connexions HTTP, FTP, SSH et les entrées / sorties peuvent également être diffusées.


Que dit wikipedia sur le concept de streaming?

En informatique, un flux est une séquence d'éléments de données rendus disponibles au fil du temps. Un flux peut être considéré comme des articles sur une bande transporteuse traités un par un plutôt que par lots importants.

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

Wikipédia liens vers ceci: https://srfi.schemers.org/srfi-41/srfi-41.html et les auteurs ont ceci à dire à propos des flux:

Les flux, parfois appelés listes différées, sont une structure de données séquentielle contenant des éléments calculés uniquement à la demande. Un flux est nul ou est une paire avec un flux dans son cdr. Étant donné que les éléments d'un flux ne sont calculés que lors de l'accès, les flux peuvent être infinis.

Un Stream est donc en fait une structure de données.


Ma conclusion: un flux est une source qui peut contenir des données qui peuvent être lues ou écrites de manière séquentielle. Un flux ne lit pas tout ce que la source contient à la fois, il lit / écrit séquentiellement.


Liens utiles:

  1. http://www.slideshare.net/auroraeosrose/writing-and-using-php-streams-and-sockets-zendcon-2011 Fournit une présentation très claire
  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
julien
la source
4

C'est juste un concept, un autre niveau d'abstraction qui vous facilite la vie. Et ils ont tous une interface commune, ce qui signifie que vous pouvez les combiner à la manière d'un tuyau. Par exemple, encodez en base64, puis zippez et écrivez ceci sur le disque et le tout sur une seule ligne!

vava
la source
C'est utile, certes, mais je ne dirais pas que c'est le «point entier». Même sans chaîner, il est utile d'avoir une abstraction commune.
Jon Skeet
Oui vous avez raison. J'ai changé les mots pour que cela soit clair.
vava le
Ouais, c'est mieux. J'espère que vous ne pensiez pas que j'étais trop difficile!
Jon Skeet le
3

La meilleure explication des flux que j'ai vue est le chapitre 3 de SICP . (Vous devrez peut-être lire les 2 premiers chapitres pour que cela ait du sens, mais vous devriez quand même. :-)

Ils n'utilisent pas du tout des stérams pour les octets, mais plutôt des entiers. Les principaux points que j'en ai tirés étaient:

  • Les flux sont des listes retardées
  • La surcharge de calcul [du calcul avide de tout à l'avance, dans certains cas] est scandaleuse
  • Nous pouvons utiliser des flux pour représenter des séquences infiniment longues
Ken
la source
Je suis actuellement sur le chapitre 1 du SICP. Merci!
Rob Sobers
2
on aimerait distinguer le flux SICP des autres. une caractéristique importante de flux SICP est la paresse , alors que le générique flux notion met l' accent sur l' abstraction sur des séquences de données .
象 嘉 道
2

Un autre point (pour la situation de lecture de fichier):

  1. streampeut vous permettre de faire autre chose avant finished reading all content of the file.
  2. vous pouvez économiser de la mémoire, car vous n'avez pas besoin de charger tout le contenu du fichier à la fois.
Vikyd
la source
1

Pensez aux flux comme à une source abstraite de données (octets, caractères, etc.). Ils font abstraction des mécanismes réels de lecture et d'écriture dans la source de données concrète, qu'il s'agisse d'une socket réseau, d'un fichier sur un disque ou d'une réponse du serveur Web.

Anton Gogolev
la source
1

Je pense que vous devez considérer que le backing store lui-même n'est souvent qu'une autre abstraction. Un flux de mémoire est assez facile à comprendre, mais un fichier est radicalement différent selon le système de fichiers que vous utilisez, sans parler du disque dur que vous utilisez. En fait, tous les flux ne sont pas placés au-dessus d'un magasin de stockage: les flux réseau ne sont en fait que des flux.

Le but d'un flux est que nous limitons notre attention à ce qui est important. En ayant une abstraction standard, nous pouvons effectuer des opérations courantes. Même si vous ne voulez pas, par exemple, rechercher un fichier ou une réponse HTTP pour les URL aujourd'hui, cela ne signifie pas que vous ne le souhaiterez pas demain.

Les flux ont été conçus à l'origine lorsque la mémoire était minime par rapport au stockage. La simple lecture d'un fichier C peut être une charge importante. Minimiser l'empreinte mémoire était extrêmement important. Par conséquent, une abstraction dans laquelle très peu de choses devaient être chargées était très utile. Aujourd'hui, il est également utile lors de la communication réseau et, il s'avère, rarement aussi restrictif lorsque nous traitons des fichiers. La possibilité d'ajouter de manière transparente des éléments tels que la mise en mémoire tampon de manière générale le rend encore plus utile.

Julian Birch
la source
0

Un flux est un résumé d'une séquence d'octets. L'idée est que vous n'avez pas besoin de savoir d'où viennent les octets, mais simplement que vous pouvez les lire de manière standardisée.

Par exemple, si vous traitez des données via un flux, cela n'a pas d'importance pour votre code si les données proviennent d'un fichier, d'une connexion réseau, d'une chaîne, d'un objet blob dans une base de données, etc.

Il n'y a rien de mal en soi à interagir avec le magasin de sauvegarde lui-même, sauf le fait qu'il vous lie à l'implémentation du magasin de sauvegarde.

Sean
la source
0

Un flux est une abstraction qui fournit un ensemble standard de méthodes et de propriétés pour interagir avec les données. En supprimant le support de stockage réel, votre code peut être écrit sans dépendre totalement de ce qu'est ce support ou même de l'implémentation de ce support.

Une bonne analogie pourrait être de considérer un sac. Peu importe de quoi est fait un sac ou ce qu'il fait lorsque vous y mettez vos affaires, du moment que le sac remplit le rôle de sac et que vous pouvez récupérer vos affaires. Un flux définit pour les supports de stockage ce que le concept de sac définit pour différentes instances d'un sac (comme le sac poubelle, le sac à main, le sac à dos, etc.) - les règles d'interaction.

Jeff Yates
la source
0

Je vais être bref, je manquais juste le mot ici:

Les flux sont des files d'attente généralement stockées dans un tampon contenant tout type de données.

(Maintenant, puisque nous savons tous ce que sont les files d'attente, il n'est pas nécessaire de l'expliquer davantage.)

Marcus
la source