Können Sie das Konzept der Streams erklären?


186

Ich verstehe, dass ein Stream eine Darstellung einer Folge von Bytes ist. Jeder Stream bietet Mittel zum Lesen und Schreiben von Bytes in den angegebenen Sicherungsspeicher. Aber worum geht es im Stream? Warum ist der Hintergrundspeicher selbst nicht das, mit dem wir interagieren?

Aus irgendeinem Grund klickt dieses Konzept einfach nicht für mich. Ich habe eine Reihe von Artikeln gelesen, aber ich glaube, ich brauche eine Analogie oder so.

Antworten:


234

Das Wort "Stream" wurde gewählt, weil es (im wirklichen Leben) eine sehr ähnliche Bedeutung hat wie das, was wir vermitteln wollen, wenn wir es verwenden.

Vergessen wir ein wenig den Hintergrundspeicher und denken über die Analogie zu einem Wasserstrom nach. Sie erhalten einen kontinuierlichen Datenfluss, genau wie Wasser kontinuierlich in einem Fluss fließt. Sie wissen nicht unbedingt, woher die Daten stammen, und müssen dies meistens nicht. Sei es aus einer Datei, einem Socket oder einer anderen Quelle, es spielt keine Rolle (sollte). Dies ist sehr ähnlich wie das Empfangen eines Wasserstroms, wobei Sie nicht wissen müssen, woher es kommt. sei es aus einem See, einem Brunnen oder einer anderen Quelle, es spielt keine Rolle (sollte).

Das heißt, sobald Sie anfangen zu denken, dass Sie sich nur darum kümmern, die Daten zu erhalten, die Sie benötigen, unabhängig davon, woher sie stammen, werden die Abstraktionen, über die andere gesprochen haben, klarer. Sie denken, dass Sie Streams umbrechen können und Ihre Methoden immer noch perfekt funktionieren. Zum Beispiel könnten Sie dies tun:

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

Wie Sie sehen, ist es sehr einfach, Ihre Eingangsquelle zu ändern, ohne Ihre Verarbeitungslogik zu ändern. So lesen Sie beispielsweise Ihre Daten von einem Netzwerk-Socket anstelle einer Datei:

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

So einfach wie es nur geht. Und die Schönheit geht weiter, da Sie jede Art von Eingabequelle verwenden können, solange Sie einen Stream- "Wrapper" dafür erstellen können. Sie könnten dies sogar tun:

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

Sehen? Solange es Ihrer Methode egal ist, um welche Eingabequelle es sich handelt, können Sie Ihre Quelle auf verschiedene Arten anpassen. Mit der Abstraktion können Sie Eingaben auf sehr elegante Weise von der Verarbeitungslogik entkoppeln.

Beachten Sie, dass der Stream, den wir selbst erstellt haben, keinen Hintergrundspeicher hat, aber dennoch perfekt unseren Zwecken dient.

Zusammenfassend ist ein Stream also nur eine Eingabequelle, die eine andere Quelle verbirgt (abstrahiert). Solange Sie die Abstraktion nicht brechen, ist Ihr Code sehr flexibel.


6
Abstraktes Denken (und Erklären) scheint in deinem Blut zu liegen;) Deine Analogie zu Wasser (und damit metaphorische Bezüge) erinnerte mich an Omar Khayyam.
java.is.for.desktop

@HosamAly Ihre Erklärung ist sehr klar, aber etwas verwirrt mich ein bisschen im Beispielcode. Die explizite Konvertierung von string nach int erfolgt automatisch mit ReadInt? Ich glaube, ich könnte auch ReadString machen?
Rushino

1
@Rushino Der obige Code enthält keine Konvertierungen. Die Methode ReadIntwird ganz oben mit definiert int.Parse, wobei die zurückgegebene Zeichenfolge empfangen reader.ReadLine()und analysiert wird. Natürlich können Sie eine ähnliche ReadStringMethode erstellen . Ist das klar genug?
Hosam Aly

Gut ausgedrückt. Streams sind für mich die einfachsten und leistungsfähigsten generischen Abstraktionen in der gesamten Programmierung. Mit .net basic wird Stream.Copydas Leben in vielen Anwendungen so viel einfacher.
Felype

38

Der Punkt ist, dass Sie nicht wissen müssen, was der Hintergrundspeicher ist - es ist eine Abstraktion darüber. Tatsächlich könnte es nicht einmal sein ein Sicherungsspeicher - man von einem Netz liest könnte, und die Daten werden überhaupt nicht „gespeichert“.

Wenn Sie Code schreiben können, der funktioniert, unabhängig davon, ob Sie mit einem Dateisystem, einem Speicher, einem Netzwerk oder etwas anderem sprechen, das die Stream-Idee unterstützt, ist Ihr Code viel flexibler.

Außerdem werden Streams häufig miteinander verkettet - Sie können einen Stream haben, der alles komprimiert, was in ihn eingefügt wird, das komprimierte Formular in einen anderen Stream schreibt oder der die Daten verschlüsselt usw. Am anderen Ende gibt es das Gegenteil Kette, Entschlüsselung, Dekomprimierung oder was auch immer.


Bedeuten die verschiedenen Arten von Stream-Readern, die im obigen @ HosamAly-Beispiel verwendet werden, nicht, dass Sie wissen, was der Hintergrundspeicher ist? Ich nehme an, FileStream, NetworkStream usw. lesen aus solchen Quellen. Gibt es außerdem Fälle, in denen Sie nicht wissen, wie der Sicherungsspeicher aussehen könnte, und die dynamisch ausgewählt werden, während das Programm ausgeführt wird? Ich bin einfach nicht persönlich darauf gestoßen und würde gerne mehr wissen.
user137717

Können Streams auch Daten durch einen Prozess leiten, während Daten generiert werden, oder benötige ich Zugriff auf den vollständigen Datensatz, mit dem ich arbeiten möchte, wenn ich den Prozess beginne?
user137717

@ user137717: Nein, wenn Sie nur ein StreamReader- oder besser ein - nehmen , TextReaderdann weiß Ihr Code nicht, welche Art von Stream dem Datenfluss zugrunde liegt. Oder besser gesagt, es kann die BaseStreamEigenschaft verwenden, um den Typ herauszufinden - aber es kann ein Typ sein, den Ihr Code noch nie zuvor gesehen hat. Der Punkt ist, dass Sie sich nicht darum kümmern sollten. Und ja, Sie können am Ende durchaus Code schreiben, der manchmal für einen Netzwerkstrom und manchmal für einen Dateistream verwendet wird. Was Streams betrifft, die Daten durch einen Prozess leiten - nun, das würde nicht innerhalb des Prozesses geschehen ... es wäre der Stream-Anbieter.
Jon Skeet

30

Der Zweck des Streams besteht darin, eine Abstraktionsebene zwischen Ihnen und dem Hintergrundspeicher bereitzustellen. Daher muss es einem bestimmten Codeblock, der einen Stream verwendet, egal sein, ob der Sicherungsspeicher eine Festplattendatei, ein Speicher usw. ist.


Ja, Sie können den Stream-Typ austauschen, ohne Ihren Code zu beschädigen. Sie können beispielsweise bei einem Aufruf aus einer Datei und beim nächsten aus einem Speicherpuffer einlesen.
Craig

Ich würde hinzufügen, dass der Grund, warum Sie dies tun möchten, darin besteht, dass Sie beim Lesen oder Schreiben einer Datei häufig keine Dateisuchfunktion benötigen. Wenn Sie also einen Stream verwenden, kann derselbe Code problemlos zum Lesen oder Schreiben verwendet werden Zum Beispiel einen Netzwerk-Socket.
Alxp

11

Es geht nicht um Bäche - es geht ums Schwimmen. Wenn Sie einen Stream schwimmen können, können Sie jeden Stream schwimmen, dem Sie begegnen.


7

Um die Echokammer zu erweitern, ist der Stream eine Abstraktion, sodass Sie sich nicht um den zugrunde liegenden Speicher kümmern. Dies ist am sinnvollsten, wenn Sie Szenarien mit und ohne Streams betrachten.

Dateien sind größtenteils uninteressant, da Streams nicht viel über die mir bekannten nicht-streambasierten Methoden hinaus tun. Beginnen wir mit Internetdateien.

Wenn ich eine Datei aus dem Internet herunterladen möchte, muss ich einen TCP-Socket öffnen, eine Verbindung herstellen und Bytes empfangen, bis keine Bytes mehr vorhanden sind. Ich muss einen Puffer verwalten, die Größe der erwarteten Datei kennen und Code schreiben, um zu erkennen, wann die Verbindung getrennt wird, und dies entsprechend behandeln.

Angenommen, ich habe eine Art TcpDataStream-Objekt. Ich erstelle es mit den entsprechenden Verbindungsinformationen und lese dann Bytes aus dem Stream, bis es heißt, dass keine Bytes mehr vorhanden sind. Der Stream übernimmt die Pufferverwaltung, die Datenendbedingungen und die Verbindungsverwaltung.

Auf diese Weise erleichtern Streams die E / A. Sie könnten sicherlich eine TcpFileDownloader-Klasse schreiben, die das tut, was der Stream tut, aber dann haben Sie eine Klasse, die spezifisch für TCP ist. Die meisten Stream-Schnittstellen bieten lediglich eine Read () - und eine Write () -Methode, und kompliziertere Konzepte werden von der internen Implementierung behandelt. Aus diesem Grund können Sie denselben Basiscode zum Lesen oder Schreiben in Speicher, Festplattendateien, Sockets und viele andere Datenspeicher verwenden.


5

Die Visualisierung, die ich verwende, sind Förderbänder, nicht in echten Fabriken, weil ich nichts darüber weiß, sondern in Cartoon-Fabriken, in denen sich Gegenstände entlang von Linien bewegen und von einer Reihe dummer Geräte gestempelt und verpackt und gezählt und überprüft werden.

Sie haben einfache Komponenten, die eines tun, zum Beispiel ein Gerät, mit dem Sie eine Kirsche auf einen Kuchen legen können. Dieses Gerät verfügt über einen Eingangsstrom von kirschlosen Kuchen und einen Ausgangsstrom von Kuchen mit Kirschen. Es gibt drei erwähnenswerte Vorteile, wenn Sie Ihre Verarbeitung auf diese Weise strukturieren.

Erstens vereinfacht es die Komponenten selbst: Wenn Sie Schokoladenglasur auf einen Kuchen legen möchten, benötigen Sie kein kompliziertes Gerät, das alles über Kuchen weiß. Sie können ein dummes Gerät erstellen, das Schokoladenglasur auf alles klebt, was in den Kuchen eingespeist wird (in Bei den Cartoons geht dies so weit, dass man nicht weiß, dass der nächste Gegenstand kein Kuchen ist, sondern Wile E. Coyote.

Zweitens können Sie verschiedene Produkte erstellen, indem Sie die Geräte in verschiedene Sequenzen einordnen: Vielleicht möchten Sie, dass Ihre Kuchen auf der Kirsche statt auf dem Zuckerguss vereist sind, und Sie können dies einfach tun, indem Sie die Geräte auf der Linie vertauschen .

Drittens müssen die Geräte kein Inventar, Boxen oder Unboxing verwalten. Die effizienteste Art, Dinge zu aggregieren und zu verpacken, ist veränderbar: Vielleicht legen Sie Ihre Kuchen heute in Kartons mit 48 Stück und versenden sie per LKW-Ladung, aber morgen möchten Sie Kartons mit sechs Stück als Antwort auf Sonderanfertigungen versenden. Diese Art von Änderung kann durch Ersetzen oder Neukonfigurieren der Maschinen am Anfang und Ende der Produktionslinie berücksichtigt werden. Die Kirschmaschine in der Mitte der Zeile muss nicht geändert werden, um eine andere Anzahl von Elementen gleichzeitig zu verarbeiten. Sie arbeitet immer mit jeweils einem Element und muss nicht wissen, wie die Eingabe oder Ausgabe erfolgt gruppiert werden.


Tolles Beispiel für Analogie als Erklärung.
Richie Thomas

5

Als ich zum ersten Mal von Streaming hörte, war es im Zusammenhang mit Live-Streaming mit einer Webcam. Ein Host sendet also Videoinhalte und der andere Host empfängt den Videoinhalt. Also ist das Streaming? Nun ... ja ... aber ein Live-Stream ist ein konkretes Konzept, und ich denke, dass sich die Frage auf das abstrakte Konzept des Streamings bezieht. Siehe https://en.wikipedia.org/wiki/Live_streaming

Also lasst uns weitermachen.


Video ist nicht die einzige Ressource, die gestreamt werden kann. Audio kann auch gestreamt werden. Wir sprechen jetzt über Streaming Media. Siehe https://en.wikipedia.org/wiki/Streaming_media . Audio kann auf vielfältige Weise von der Quelle zum Ziel übertragen werden. Vergleichen wir also einige Datenübermittlungsmethoden miteinander.

Herunterladen klassischer Dateien Das Herunterladen klassischer Dateien erfolgt nicht in Echtzeit. Bevor Sie die Datei verwenden, müssen Sie warten, bis der Download abgeschlossen ist.

Progressiver Download Progressive Download-Chunks laden Daten aus der gestreamten Mediendatei in einen temporären Puffer herunter. Daten in diesem Puffer können verarbeitet werden: Audio-Video-Daten im Puffer können abgespielt werden. Aus diesem Grund können Benutzer die gestreamte Mediendatei beim Herunterladen ansehen / anhören. Ein schneller Vor- und Rücklauf ist möglich, natürlich ohne Puffer. Auf jeden Fall ist progressiver Download kein Live-Streaming.

Streaming Geschieht in Echtzeit und blockiert Daten. Streaming wird in Live-Übertragungen implementiert. Clients, die die Sendung hören, können nicht vor- oder zurückspulen. In Videostreams werden Daten nach der Wiedergabe verworfen.

Ein Streaming-Server unterhält eine bidirektionale Verbindung zu seinem Client, während ein Webserver die Verbindung nach einer Serverantwort schließt.


Audio und Video sind nicht das einzige, was gestreamt werden kann. Schauen wir uns das Konzept der Streams im PHP-Handbuch an.

Ein Stream ist ein Ressourcenobjekt, das ein streambares Verhalten aufweist. Das heißt, es wird gelesen von oder geschrieben in einer linearen Weise, und kann in der Lage sein , innerhalb des Stroms () an eine beliebige Stelle auf fseek. Link: https://www.php.net/manual/en/intro.stream.php

In PHP ist eine Ressource ein Verweis auf eine externe Quelle wie eine Datei oder eine Datenbankverbindung. Mit anderen Worten, ein Stream ist eine Quelle, aus der gelesen oder geschrieben werden kann. Wenn Sie also mit gearbeitet haben fopen(), haben Sie bereits mit Streams gearbeitet.

Ein Beispiel für eine Textdatei, die einem Streaming unterzogen wird:

// 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

Zip-Dateien können auch gestreamt werden. Darüber hinaus ist das Streaming nicht auf Dateien beschränkt. HTTP-, FTP-, SSH-Verbindungen und Input / Output können ebenfalls gestreamt werden.


Was sagt Wikipedia über das Konzept des Streamings?

In der Informatik ist ein Stream eine Folge von Datenelementen, die im Laufe der Zeit verfügbar gemacht werden. Ein Strom kann als Artikel auf einem Förderband betrachtet werden, die einzeln und nicht in großen Mengen verarbeitet werden.

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

Wikipedia-Links dazu: https://srfi.schemers.org/srfi-41/srfi-41.html und die Autoren haben Folgendes zu Streams zu sagen:

Streams, manchmal auch Lazy Lists genannt, sind eine sequentielle Datenstruktur, die Elemente enthält, die nur bei Bedarf berechnet werden. Ein Stream ist entweder null oder ein Paar mit einem Stream in seiner CDR. Da Elemente eines Streams nur beim Zugriff berechnet werden, können Streams unendlich sein.

Ein Stream ist also eigentlich eine Datenstruktur.


Mein Fazit: Ein Stream ist eine Quelle, die Daten enthalten kann, aus denen sequentiell gelesen oder geschrieben werden kann. Ein Stream liest nicht alles, was die Quelle enthält, auf einmal, sondern liest / schreibt nacheinander.


Nützliche Links:

  1. http://www.slideshare.net/auroraeosrose/writing-and-using-php-streams-and-sockets-zendcon-2011 Bietet eine sehr übersichtliche Darstellung
  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

4

Es ist nur ein Konzept, eine andere Abstraktionsebene, die Ihnen das Leben erleichtert. Und alle haben eine gemeinsame Schnittstelle, was bedeutet, dass Sie sie pfeifenartig kombinieren können. Zum Beispiel in base64 codieren, dann komprimieren und dann auf die Festplatte schreiben und alles in einer Zeile!


Das ist sicherlich nützlich, aber ich würde nicht sagen, dass es der "springende Punkt" ist. Auch ohne Verkettung ist es nützlich, eine gemeinsame Abstraktion zu haben.
Jon Skeet

Ja, du hast recht. Ich habe die Wörter geändert, um dies klar zu machen.
Vava

Ja, das ist besser. Ich hoffe du hast nicht gedacht, dass ich zu wählerisch bin!
Jon Skeet

3

Die beste Erklärung für Streams, die ich gesehen habe, ist Kapitel 3 von SICP . (Möglicherweise müssen Sie die ersten beiden Kapitel lesen, damit es Sinn macht, aber Sie sollten es trotzdem tun. :-)

Sie verwenden überhaupt keine Sterame für Bytes, sondern ganze Zahlen. Die großen Punkte, die ich daraus bekam, waren:

  • Streams sind verzögerte Listen
  • Der Rechenaufwand [in einigen Fällen eifrig alles im Voraus zu berechnen] ist unverschämt
  • Wir können Streams verwenden, um Sequenzen darzustellen, die unendlich lang sind

Ich bin gerade in Kapitel 1 von SICP. Vielen Dank!
Rob Sobers

2
man möchte SICP-Stream von anderen erzählen . ein wichtiges Merkmal der SICP Strom ist Faulheit , während der allgemeine Strom Konzept der betont Abstraktion auf Datensequenzen .
嘉 道

2

Ein weiterer Punkt (zum Lesen der Dateisituation):

  1. streamkann Ihnen erlauben, vorher etwas anderes zu tun finished reading all content of the file.
  2. Sie können Speicherplatz sparen, da nicht der gesamte Dateiinhalt auf einmal geladen werden muss.

1

Stellen Sie sich Streams als abstrakte Datenquelle vor (Bytes, Zeichen usw.). Sie abstrahieren die tatsächlichen Mechanismen des Lesens und Schreibens aus der konkreten Datenquelle, sei es ein Netzwerksocket, eine Datei auf einer Festplatte oder eine Antwort vom Webserver.


1

Ich denke, Sie müssen berücksichtigen, dass der Hintergrundspeicher selbst oft nur eine andere Abstraktion ist. Ein Speicherstrom ist ziemlich einfach zu verstehen, aber eine Datei unterscheidet sich radikal, je nachdem, welches Dateisystem Sie verwenden, unabhängig davon, welche Festplatte Sie verwenden. Tatsächlich befinden sich nicht alle Streams auf einem Backing Store: Netzwerk-Streams sind so ziemlich nur Streams.

Der Punkt eines Streams ist, dass wir unsere Aufmerksamkeit auf das beschränken, was wichtig ist. Durch eine Standardabstraktion können wir allgemeine Operationen ausführen. Auch wenn Sie beispielsweise heute keine Datei oder HTTP-Antwort nach URLs durchsuchen möchten, heißt das nicht, dass Sie es morgen nicht möchten.

Streams wurden ursprünglich konzipiert, als der Speicher im Vergleich zum Speicher winzig war. Das Lesen einer C-Datei kann eine erhebliche Belastung darstellen. Die Minimierung des Speicherbedarfs war äußerst wichtig. Daher war eine Abstraktion, in die nur sehr wenig geladen werden musste, sehr nützlich. Heutzutage ist es bei der Netzwerkkommunikation gleichermaßen nützlich und, wie sich herausstellt, beim Umgang mit Dateien selten so restriktiv. Die Möglichkeit, Dinge wie das allgemeine Puffern transparent hinzuzufügen, macht es noch nützlicher.


0

Ein Stream ist eine Abstraktion einer Folge von Bytes. Die Idee ist, dass Sie nicht wissen müssen, woher die Bytes kommen, sondern dass Sie sie auf standardisierte Weise lesen können.

Wenn Sie beispielsweise Daten über einen Stream verarbeiten, spielt es für Ihren Code keine Rolle, ob die Daten aus einer Datei, einer Netzwerkverbindung, einer Zeichenfolge, einem Blob in einer Datenbank usw. usw. stammen.

An sich ist nichts Falsches an der Interaktion mit dem Backing Store selbst, außer der Tatsache, dass Sie damit an die Implementierung des Backing Stores gebunden sind.


0

Ein Stream ist eine Abstraktion, die einen Standardsatz von Methoden und Eigenschaften für die Interaktion mit Daten bereitstellt. Durch Abstrahieren vom eigentlichen Speichermedium kann Ihr Code geschrieben werden, ohne sich vollständig auf das Medium oder die Implementierung dieses Mediums zu verlassen.

Eine gute Analogie könnte darin bestehen, eine Tasche in Betracht zu ziehen. Es ist dir egal, woraus eine Tasche besteht oder was sie tut, wenn du deine Sachen hineinlegst, solange die Tasche die Aufgabe erfüllt, eine Tasche zu sein und du deine Sachen wieder herausholen kannst. Ein Stream definiert für Speichermedien, was das Konzept des Beutels für verschiedene Instanzen eines Beutels (wie Müllsack, Handtasche, Rucksack usw.) definiert - die Regeln der Interaktion.


0

Ich werde mich kurz fassen, mir hat hier nur das Wort gefehlt:

Streams sind Warteschlangen, die normalerweise in einem Puffer gespeichert sind, der Daten jeglicher Art enthält.

(Da wir alle wissen, was Warteschlangen sind, müssen wir dies nicht weiter erklären.)

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.