Was ist ein Stream?

136

Was ist ein Stream in der Programmierwelt? Warum brauchen wir es?

Bitte erklären Sie dies nach Möglichkeit anhand einer Analogie.

pokrate
quelle
10
Dies ist ein Duplikat von stackoverflow.com/questions/507747/… .
John Saunders

Antworten:

161

Ein Stream repräsentiert eine Folge von Objekten (normalerweise Bytes, aber nicht unbedingt), auf die in sequentieller Reihenfolge zugegriffen werden kann. Typische Operationen in einem Stream:

  • Lesen Sie ein Byte. Wenn Sie das nächste Mal lesen, erhalten Sie das nächste Byte und so weiter.
  • Lesen Sie mehrere Bytes aus dem Stream in ein Array
  • Suchen (Verschieben Sie Ihre aktuelle Position im Stream, damit Sie beim nächsten Lesen Bytes von der neuen Position erhalten.)
  • schreibe ein Byte
  • Schreiben Sie mehrere Bytes aus einem Array in den Stream
  • Überspringen Sie Bytes aus dem Stream (dies ist wie Lesen, aber Sie ignorieren die Daten. Oder wenn Sie es vorziehen, ist es wie Suchen, kann aber nur vorwärts gehen.)
  • Bytes in einen Eingabestream zurückschieben (dies ist wie "Rückgängig" zum Lesen - Sie schieben ein paar Bytes zurück in den Stream, so dass Sie beim nächsten Lesen das sehen werden. Es ist gelegentlich nützlich für Parser, wie es ist:
  • Peek (schau dir Bytes an, ohne sie zu lesen, damit sie noch im Stream sind, um später gelesen zu werden)

Ein bestimmter Stream unterstützt möglicherweise das Lesen (in diesem Fall handelt es sich um einen "Eingabestream"), das Schreiben ("Ausgabestream") oder beides. Nicht alle Streams sind durchsuchbar.

Push-Back ist ziemlich selten, aber Sie können es jederzeit einem Stream hinzufügen, indem Sie den realen Eingabestream in einen anderen Eingabestream einschließen, der einen internen Puffer enthält. Lesevorgänge kommen aus dem Puffer, und wenn Sie zurückschieben, werden Daten in den Puffer gestellt. Wenn sich nichts im Puffer befindet, liest der Push-Back-Stream aus dem realen Stream. Dies ist ein einfaches Beispiel für einen "Stream-Adapter": Er befindet sich am "Ende" eines Eingabestreams, ist selbst ein Eingabestream und macht etwas Besonderes, das der ursprüngliche Stream nicht getan hat.

Stream ist eine nützliche Abstraktion, da es Dateien (die wirklich Arrays sind, daher ist das Suchen unkompliziert), aber auch Terminal-Ein- / Ausgabe (die nur durchsucht werden kann, wenn sie gepuffert sind), Sockets, serielle Schnittstellen usw. beschreiben kann. Sie können also Code schreiben, der besagt Entweder "Ich möchte einige Daten, und es ist mir egal, woher sie kommen oder wie sie hierher gekommen sind" oder "Ich werde einige Daten produzieren und es liegt ganz bei meinem Anrufer, was damit passiert". Ersteres verwendet einen Eingabestream-Parameter, letzteres einen Ausgabestream-Parameter.

Die beste Analogie, die ich mir vorstellen kann, ist, dass ein Strom ein Förderband ist, das auf Sie zukommt oder von Ihnen wegführt (oder manchmal beides). Sie entfernen Inhalte aus einem Eingabestream, Sie fügen Inhalte in einen Ausgabestream ein. Einige Förderer, die Sie sich vorstellen können, kommen aus einem Loch in der Wand - sie sind nicht suchbar, Lesen oder Schreiben ist ein einmaliger Deal. Einige Förderer sind vor Ihnen angeordnet, und Sie können den Aufenthaltsort in dem Stream auswählen, den Sie lesen / schreiben möchten - das ist die Suche.

Wie IRBMe jedoch sagt, ist es am besten, sich einen Stream in Bezug auf die von ihm angebotenen Operationen vorzustellen (die von Implementierung zu Implementierung variieren, aber viel gemeinsam haben) und nicht durch eine physikalische Analogie. Streams sind "Dinge, die man lesen oder schreiben kann". Wenn Sie mit dem Anschließen von Stream-Adaptern beginnen, können Sie sich diese als eine Box mit einem Förderer in und einem Förderer aus vorstellen, die Sie mit anderen Streams verbinden. Anschließend führt die Box eine Transformation der Daten durch (Komprimieren oder Ändern von UNIX-Zeilenvorschüben) zu DOS oder was auch immer). Pipes sind ein weiterer gründlicher Test der Metapher: Hier erstellen Sie ein Paar Streams, sodass alles, was Sie in einen schreiben, aus dem anderen ausgelesen werden kann. Denk an Wurmlöcher :-)

Steve Jessop
quelle
3
Mit Abstand die beste Erklärung, die ich gelesen habe. In Verbindung mit dem, was in SICP steht ("Mit der Stream-Verarbeitung können wir Systeme modellieren, die einen Status haben, ohne jemals Zuweisungen oder veränderbare Daten zu verwenden."), Denke ich, dass ich es endlich verstehe. Danke dir!
Kyle Chadha
85

Ein Stream ist bereits eine Metapher, eine Analogie, so dass es wirklich nicht nötig ist, einen anderen zu veröffentlichen. Sie können es sich im Grunde als ein Rohr mit einem Wasserfluss vorstellen, in dem das Wasser tatsächlich Daten und das Rohr der Strom ist. Ich nehme an, es ist eine Art 2-Wege-Rohr, wenn der Strom bidirektional ist. Es ist im Grunde eine übliche Abstraktion, die auf Dinge angewendet wird, bei denen ein Datenfluss oder eine Folge von Daten in eine oder beide Richtungen vorliegt.

In Sprachen wie C #, VB.Net, C ++, Java usw. wird die Stream-Metapher für viele Dinge verwendet. Es gibt Dateistreams, in denen Sie eine Datei öffnen und kontinuierlich aus dem Stream lesen oder darauf schreiben können. Es gibt Netzwerk-Streams, in denen das Lesen von und das Schreiben in den Stream von einer zugrunde liegenden etablierten Netzwerkverbindung liest und in diese schreibt. Streams, die nur zum Schreiben verwendet werden, werden normalerweise wie in diesem Beispiel als Ausgabestreams bezeichnet. In ähnlicher Weise werden Streams, die nur zum Lesen bestimmt sind, wie in diesem Beispiel als Eingabestreams bezeichnet .

Ein Stream kann eine Transformation oder Codierung von Daten durchführen (ein SslStream in .Net verschlingt beispielsweise die SSL-Verhandlungsdaten und verbirgt sie vor Ihnen; Ein TelnetStream kann die Telnet-Verhandlungen vor Ihnen verbergen, bietet jedoch Zugriff auf die Daten; A. Mit ZipOutputStream in Java können Sie in Dateien in einem Zip-Archiv schreiben, ohne sich um die Interna des Zip-Dateiformats kümmern zu müssen.

Eine andere häufige Sache, die Sie möglicherweise finden, sind Text-Streams, mit denen Sie Zeichenfolgen anstelle von Bytes schreiben können, oder einige Sprachen bieten Binär-Streams, mit denen Sie primitive Typen schreiben können. Eine häufige Sache, die Sie in Textströmen finden, ist eine Zeichenkodierung, die Sie kennen sollten.

Einige Streams unterstützen auch den Direktzugriff, wie in diesem Beispiel. Ein Netzwerk-Stream hingegen würde dies aus offensichtlichen Gründen nicht tun.

UNIX-ähnliche Betriebssysteme unterstützen auch das Stream-Modell mit Programmeingabe und -ausgabe, wie hier beschrieben .

IRBMe
quelle
13

Die bisher gegebenen Antworten sind ausgezeichnet. Ich stelle nur eine andere zur Verfügung, um hervorzuheben, dass ein Stream keine Folge von Bytes oder spezifisch für eine Programmiersprache ist, da das Konzept universell ist (während seine Implementierung möglicherweise eindeutig ist). Ich sehe online oft eine Fülle von Erklärungen in Bezug auf SQL, C oder Java, die sinnvoll sind, da sich ein Dateistream mit Speicherorten und Operationen auf niedriger Ebene befasst. Sie befassen sich jedoch häufig mit der Erstellung eines Dateistreams und der Bearbeitung der potenziellen Datei in der angegebenen Sprache, anstatt das Konzept eines Streams zu diskutieren.

Die Metapher

Wie bereits erwähnt, streamist a eine Metapher, eine Abstraktion von etwas Komplexerem. Um Ihre Fantasie zum Laufen zu bringen, biete ich einige andere Metaphern an:

  1. Sie möchten einen leeren Pool mit Wasser füllen. Eine Möglichkeit, dies zu erreichen, besteht darin, einen Schlauch an einem Zapfen zu befestigen, das Schlauchende in den Pool zu legen und das Wasser einzuschalten.

Der Schlauch ist der Strom

  1. Wenn Sie Ihr Auto mit Benzin auffüllen möchten, gehen Sie zu einer Zapfsäule, setzen die Düse in Ihren Gastank ein und öffnen das Ventil durch Drücken des Verriegelungshebels.

Der Schlauch, die Düse und die zugehörigen Mechanismen, damit das Gas in Ihren Tank strömen kann, sind der Strom

  1. Wenn Sie zur Arbeit müssen, fahren Sie über die Autobahn von zu Hause ins Büro.

Die Autobahn ist der Strom

  1. Wenn Sie ein Gespräch mit jemandem führen möchten, verwenden Sie Ihre Ohren zum Hören und Ihren Mund zum Sprechen.

Deine Ohren und Augen sind Ströme

Hoffentlich bemerken Sie in diesen Beispielen, dass die Stream-Metaphern nur existieren, um etwas durch sie hindurch zu lassen (oder im Fall der Autobahn darauf) und nicht selbst immer das darstellen, was sie übertragen. Eine wichtige Unterscheidung. Wir bezeichnen unsere Ohren nicht als eine Folge von Wörtern. Ein Schlauch ist immer noch ein Schlauch, wenn kein Wasser durch ihn fließt, aber wir müssen ihn an einen Zapfen anschließen, damit er seine Arbeit korrekt erledigt. Ein Auto ist nicht die einzige Art von Fahrzeug, die eine Autobahn überqueren kann.

Somit kann ein Stream existieren, durch den keine Daten übertragen werden, solange er mit einer Datei verbunden ist .

Abstraktion entfernen

Als nächstes müssen wir einige Fragen beantworten. Ich werde Dateien verwenden, um Streams zu beschreiben, also ... Was ist eine Datei? Und wie lesen wir eine Datei? Ich werde versuchen, dies unter Beibehaltung eines bestimmten Abstraktionsniveaus zu beantworten, um unnötige Komplexität zu vermeiden, und das Konzept einer Datei aufgrund ihrer Einfachheit und Zugänglichkeit relativ zu einem Linux-Betriebssystem verwenden.

Was ist eine Datei?

Eine Datei ist eine Abstraktion :)

Oder, so einfach ich erklären kann, ist eine Datei eine Teiledatenstruktur, die die Datei beschreibt, und ein Teil Daten, die den eigentlichen Inhalt darstellen.

Der Datenstrukturteil (in UNIX / Linux-Systemen als Inode bezeichnet) identifiziert wichtige Informationen zum Inhalt, enthält jedoch nicht den Inhalt selbst (oder einen Namen der Datei). Eine der darin enthaltenen Informationen ist eine Speicheradresse, an der der Inhalt beginnt. Mit einem Dateinamen (oder einem festen Link unter Linux), einem Dateideskriptor (einem numerischen Dateinamen, den das Betriebssystem interessiert) und einem Startort im Speicher haben wir etwas, das wir als Datei bezeichnen können.

(Der Schlüssel zum Mitnehmen ist, dass eine 'Datei' vom Betriebssystem definiert wird, da es das Betriebssystem ist, das sich letztendlich damit befassen muss. Und ja, Dateien sind viel komplexer.)

So weit, ist es gut. Aber wie bekommen wir den Inhalt der Datei, sagen Sie Ihrem Freund einen Liebesbrief, damit wir ihn ausdrucken können?

Eine Datei lesen

Wenn wir vom Ergebnis ausgehen und rückwärts gehen, wird beim Öffnen einer Datei auf unserem Computer der gesamte Inhalt auf unseren Bildschirm gespritzt, damit wir ihn lesen können. Aber wie? Sehr methodisch ist die Antwort. Der Inhalt der Datei selbst ist eine andere Datenstruktur. Angenommen, ein Array von Zeichen. Wir können uns das auch als String vorstellen.

Wie lesen wir diesen String? Indem Sie den Speicherort im Speicher finden und unsere Zeichenreihe zeichenweise durchlaufen, bis Sie ein Zeichen am Ende der Datei erreicht haben. Mit anderen Worten ein Programm.

Ein Stream wird beim Aufrufen seines Programms erstellt und verfügt über einen Speicherort, an den eine Verbindung hergestellt oder eine Verbindung hergestellt werden kann . Ähnlich wie in unserem Beispiel für einen Wasserschlauch ist der Schlauch unwirksam, wenn er nicht an einen Zapfen angeschlossen ist. Im Fall des Streams muss er mit einer Datei verbunden sein, damit er existiert.

Streams können weiter verfeinert werden, z. B. ein Stream zum Empfangen von Eingaben oder ein Stream zum Senden von Dateiinhalten an die Standardausgabe. UNIX / Linux verbindet und hält 3 Dateistreams für uns auf Anhieb offen, stdin (Standardeingabe), stdout (Standardeingabe) und stderr (Standardfehler). Streams können als Datenstrukturen selbst oder als Objekte erstellt werden, wodurch wir komplexere Operationen des durch sie gestreamten Datenstroms ausführen können, z. B. das Öffnen des Streams, das Schließen des Streams oder die Fehlerprüfung der Datei, mit der ein Stream verbunden ist. C ++ cinist ein Beispiel für ein Stream-Objekt.

Wenn Sie dies wünschen, können Sie sicherlich Ihren eigenen Stream schreiben.

Definition

Ein Stream ist ein wiederverwendbarer Code, der die Komplexität des Umgangs mit Daten abstrahiert und gleichzeitig nützliche Operationen für Daten bereitstellt.

rekurzion
quelle
Ein Stream ist also das Medium, durch das Daten fließen. Es muss mit der Datenquelle verbunden sein und kann Operationen an sich selbst und den durch sie fließenden Daten ausführen.
KingBryan
Ja. Mein einziger Grund, eine zusätzliche Antwort zu schreiben, war zu klären, dass ein Stream existieren kann, auch wenn keine Daten durch ihn fließen. wohingegen ein Strom IRL (mit Wasser und dergleichen) aufhört, ein Strom zu sein, wenn das Wasser aufhört zu fließen, und Verwirrung stiften kann, wenn man über die Analogie nachdenkt.
rekurzion
1
Ich lerne gerade Java und Ihre Antwort hat mir geholfen, meinen Kopf darum zu wickeln.
KingBryan
6

Zusätzlich zu den oben genannten Dingen gibt es eine andere Art von Streams - wie sie in funktionalen Programmiersprachen wie Scheme oder Haskell definiert sind - eine möglicherweise unendliche Datenstruktur, die von einer Funktion bei Bedarf generiert wird.

EFraim
quelle
6

Eine andere Analogie: Sie können nicht gegen einen Stream schwimmen, deshalb können Sie nur das nächste Bit, Byte, String oder Objekt aus dem Stream nehmen, während die bereits gelesenen Daten gelöscht werden. Ein One-Way-Ticket ... oder im Grunde nur eine Warteschlange ohne Speicherung von Persistenz.

Brauchen wir also Warteschlangen? Du entscheidest.

Marcus
quelle
Es bedeutet, dass Sie in einem Stream vorwärts gehen müssen und sich nicht rückwärts bewegen können. Zusätzlich wurden frühere Daten gelöscht, während Sie
fortfahren,
5

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.

Denken Sie ü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). Quelle

Premraj
quelle