回答:
ストリームは一連のオブジェクト(通常はバイトですが、必ずしもそうである必要はありません)を表し、順次アクセスできます。ストリームに対する一般的な操作:
特定のストリームは、読み取り(「入力ストリーム」)、書き込み(「出力ストリーム」)、またはその両方をサポートする場合があります。すべてのストリームがシークできるわけではありません。
プッシュバックはかなりまれですが、実際の入力ストリームを、内部バッファーを保持する別の入力ストリームにラップすることで、いつでもストリームに追加できます。読み取りはバッファから行われ、プッシュバックするとデータがバッファに配置されます。バッファーに何もない場合、プッシュバックストリームは実際のストリームから読み取ります。これは「ストリームアダプター」の単純な例です。入力ストリームの「終わり」に位置し、入力ストリーム自体であり、元のストリームでは行われなかった追加の処理を行います。
ストリームは、ファイル(実際には配列であるため、シークが簡単です)だけでなく、ターミナルの入出力(バッファリングしない限りシークできません)、ソケット、シリアルポートなども記述できるため、有用な抽象化です。したがって、次のようなコードを記述できます。 「データが欲しいのですが、どこから来たのか、どのようにしてここに来たのかは気にしない」、または「データを作成して、それがどうなるかは呼び出し側にかかっています」。前者は入力ストリームパラメータを受け取り、後者は出力ストリームパラメータを受け取ります。
私が考えることができる最もよいアナロジーは、ストリームがあなたに向かっている、またはあなたから離れている(または両方の場合もある)コンベヤーベルトであるということです。入力ストリームからデータを取り出し、出力ストリームにデータを置きます。あなたが壁の穴から出てくると考えることができるいくつかのコンベヤ-それらはシークできない、読み取りまたは書き込みは一度限りの取引です。一部のコンベヤはあなたの前に配置されており、読み書きしたいストリーム内の場所を選択することに沿って移動できます-それはシークです。
ただし、IRBMeが言うように、ストリームは、物理的なアナロジーではなく、提供する操作(実装ごとに異なりますが、共通点が多い)の観点から考えるのが最善です。ストリームは「読み書きできるもの」です。ストリームアダプターの接続を開始すると、他のストリームに接続し、ボックスでデータを変換(圧縮またはUNIX改行の変更)するボックスと見なすことができます。 DOSのものなど)。パイプは、メタファーのもう1つの完全なテストです。ここでは、1つのストリームに書き込みを行って、他のストリームから読み取ることができるようにします。ワームホールを考える:-)
ストリームはすでにメタファーであり、類推であるため、別のストリームを表す必要は実際にはありません。基本的には、水が実際にデータであり、パイプがストリームである、水の流れのあるパイプと考えることができます。ストリームが双方向であれば、双方向パイプのようなものだと思います。これは基本的に、データのフローまたはシーケンスが一方向または双方向にある場合に適用される一般的な抽象化です。
C#、VB.Net、C ++、Javaなどの言語では、ストリームのメタファーは多くの目的で使用されます。ファイルストリームがあり、ファイルを開いて、ストリームから読み取りまたは継続的に書き込むことができます。ストリームの読み取りと書き込みが、基盤となる確立されたネットワーク接続の読み取りと書き込みを行うネットワークストリームがあります。この例のように、書き込み専用のストリームは通常、出力ストリームと呼ばれ、同様に、読み取り専用のストリームは、この例のように入力ストリームと呼ばれます。
ストリームは、データの変換またはエンコードを実行できます(たとえば、.NetのSslStreamは、SSLネゴシエーションデータを消費して非表示にします。TelnetStreamは、Telnetネゴシエーションを非表示にしますが、データへのアクセスを提供します。A JavaのZipOutputStreamを使用すると、zipファイル形式の内部を気にすることなく、zipアーカイブ内のファイルに書き込むことができます。
あなたが見つけるかもしれないもう一つの一般的なものは、バイトの代わりに文字列を書くことを可能にするテキストストリームです、またはいくつかの言語は、プリミティブ型を書くことを可能にするバイナリストリームを提供します。テキストストリームでよく見られるのは、文字エンコーディングです。
この例のように、一部のストリームはランダムアクセスもサポートしています。一方、ネットワークストリームは、明らかな理由により、そうではありません。
ここで説明するように、UNIXのようなオペレーティングシステムは、プログラムの入出力を備えたストリームモデルもサポートしています。
これまでに与えられた答えは素晴らしいです。概念は普遍的であるため(ストリームの実装は一意である可能性があります)、ストリームが一連のバイトではなく、プログラミング言語に固有のものではないことを強調するために、もう1つだけ提供します。SQL、C、またはJavaの観点からオンラインで豊富な説明をよく目にします。これは、ファイルストリームがメモリの場所と低レベルの操作を処理するときに意味があります。しかし、彼らはしばしば、ストリームの概念について議論するのではなく、ファイルストリームを作成し、特定の言語で潜在的なファイルを操作する方法を扱います。
前述のとおり、a stream
はメタファーであり、より複雑なものの抽象化です。あなたの想像力を働かせるために、私は他のいくつかの比喩を提供します:
ホースはストリームです
ガスがあなたのタンクに流れ込むことを可能にするホース、ノズルおよび関連するメカニズムはストリームです
高速道路は流れです
あなたの耳と目は小川です
うまくいけば、これらの例では、ストリームのメタファーは何かが通過できるようにするため(または高速道路の場合はその上)にのみ存在し、転送しているものを常にそれ自体がもたらすわけではないことに気付くでしょう。重要な違い。私たちは耳を一連の言葉として参照しません。水が流れていない場合でもホースはホースですが、正常に機能させるには、スピゴットに接続する必要があります。車は、高速道路を通過できる唯一の「種類の」車両ではありません。
したがって、ファイルに接続されている限り、データが流れていないストリームが存在する可能性があります。
次に、いくつかの質問に答える必要があります。ストリームの記述にファイルを使用するので、ファイルとは何ですか。そして、どのようにファイルを読み取るのですか?不必要な複雑さを回避するために、ある程度の抽象化を維持しながらこれに答えようとし、その単純さとアクセシビリティのために、Linuxオペレーティングシステムに関連するファイルの概念を使用します。
ファイルは抽象化です:)
または、私が簡単に説明できるように、ファイルは、ファイルを記述する1つの部分のデータ構造と、実際のコンテンツである1つの部分のデータです。
データ構造の部分(UNIX / Linuxシステムではiノードと呼ばれます)は、コンテンツに関する重要な情報を識別しますが、コンテンツ自体(またはその問題のファイル名)は含みません。保持する情報の1つは、コンテンツの開始位置へのメモリアドレスです。したがって、ファイル名(またはLinuxのハードリンク)、ファイル記述子(オペレーティングシステムが考慮する数値ファイル名)、およびメモリ内の開始位置を使用して、ファイルと呼ぶことができるものがあります。
(重要なポイントは、「ファイル」はオペレーティングシステムによって定義されることです。これは、最終的に処理する必要があるのがOSであるためです。そうです、ファイルははるかに複雑です)。
ここまでは順調ですね。しかし、どうすればファイルの内容を取得できますか。たとえば、あなたへのラブレターを印刷して、印刷できるようにするにはどうすればよいでしょうか。
結果から始めて後方に移動すると、コンピューターでファイルを開くと、その内容全体が画面上に表示され、読むことができます。しかし、どうやって?非常に系統的に答えがあります。ファイル自体の内容は、別のデータ構造です。文字の配列を想定します。これを文字列と考えることもできます。
では、この文字列をどのように「読み取る」のでしょうか。メモリ内の場所を見つけて、文字の配列を繰り返し処理することにより、ファイルの終わりに到達するまで一度に1文字ずつ処理します。つまり、プログラムです。
そのプログラムが呼び出され、それがためにメモリ位置を持っているときストリームは、「作成」されるにアタッチまたはに接続します。水ホースの例と同様に、ホースが栓に接続されていないと効果がありません。ストリームの場合、存在するためにはファイルに接続する必要があります。
ストリームをさらに洗練させることができます。たとえば、入力を受け取るストリームや、ファイルの内容を標準出力に送信するストリームです。UNIX / linuxは、3つのファイルストリームを接続して開いたままにします。標準入力(stdin)(標準入力)、標準出力(stdout)、標準エラー(stderr)です。ストリームは、データ構造自体またはオブジェクトとして構築できます。これにより、ストリームを開く、ストリームを閉じる、ストリームが接続されているファイルをエラーチェックするなど、ストリームを介したデータストリーミングのより複雑な操作を実行できます。C ++ cin
はストリームオブジェクトの例です。
確かに、あなたがそう選択した場合、あなたはあなた自身のストリームを書くことができます。
ストリームは再利用可能なコードであり、データを処理するための便利な操作を提供しながら、データ処理の複雑さを抽象化します。
別の類推:ストリームに対して泳ぐことはできません。そのため、次のビット、バイト、文字列、またはオブジェクトをストリームから取得できますが、既に読み取られたデータは削除されます。一方向のチケット...または基本的に、永続性を保存しないキューだけです。
では、キューは必要ですか?あなたが決める。
「ストリーム」という言葉が選択されたのは、それを使用するときに伝えたいことと(実生活では)非常に類似した意味を表すためです。
水の流れの類推について考え始めます。川に水が流れ続けているように、データの流れも途切れません。データがどこから来ているかは必ずしもわかりませんし、ほとんどの場合、その必要はありません。それがファイル、ソケット、またはその他のソースからのものであっても、それは本当に重要ではありません(すべきではありません)。これは、水の流れを受け取ることと非常に似ています。そのため、水がどこから来ているかを知る必要はありません。湖、噴水、またはその他の情報源からのものであっても、実際には重要ではありません(すべきではありません)。ソース