回答:
「ストリーム」という言葉が選択されたのは、それを使用するときに伝えたいことと(実生活では)非常に類似した意味を表すためです。
バッキングストアについて少しだけ忘れて、水の流れにたとえることを考えましょう。川に水が流れ続けているように、データの流れも途切れません。データがどこから来ているかは必ずしもわかりませんし、ほとんどの場合、その必要はありません。それがファイル、ソケット、またはその他のソースからのものであっても、それは本当に重要ではありません(すべきではありません)。これは、水の流れを受け取ることと非常に似ています。そのため、水がどこから来ているかを知る必要はありません。湖、噴水、またはその他の情報源からのものであっても、実際には重要ではありません(すべきではありません)。
とはいえ、どこから来たかに関係なく、必要なデータを取得することだけに関心があると考え始めると、他の人が話している抽象化がより明確になります。ストリームをラップできると考え始めると、メソッドは引き続き完全に機能します。たとえば、次のようにできます。
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);
ご覧のとおり、処理ロジックを変更せずに入力ソースを変更するのは非常に簡単になります。たとえば、ファイルではなくネットワークソケットからデータを読み取るには:
Stream stream = new NetworkStream(mySocket);
StreamReader reader = new StreamReader(stream);
int x = ReadInt(reader);
できる限り簡単です。そして、ストリームの「ラッパー」を構築できる限り、あらゆる種類の入力ソースを使用できるため、美しさは続きます。あなたもこれを行うことができます:
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());
見る?メソッドが入力ソースを気にしない限り、さまざまな方法でソースをカスタマイズできます。抽象化により、非常に洗練された方法で処理ロジックから入力を切り離すことができます。
自分たちで作成したストリームにはバッキングストアがありませんが、それでも目的を完全に果たします。
つまり、要約すると、ストリームは入力のソースにすぎず、別のソースを隠して(抽象化して)います。抽象化を壊さない限り、コードは非常に柔軟です。
ReadInt
はint.Parse
、を使用して最上部で定義されており、から返された文字列を受け取ってreader.ReadLine()
解析します。もちろん、同様のReadString
メソッドを作成することもできます。これで十分ですか?
Stream.Copy
すると、多くのアプリケーションでの作業が非常に簡単になります。
重要なのは、バッキングストアが何であるかを知る必要はないということです。これは抽象化です。確かに、さえないかもしれないことバッキングストア-あなたはネットワークからの読み取りすることができ、データがすべてで「保存しない」ん。
ファイルシステム、メモリ、ネットワークなど、ストリームのアイデアをサポートする何かと話しているかに関係なく機能するコードを記述できれば、コードの柔軟性が大幅に向上します。
さらに、ストリームはしばしばチェーン化されます。ストリームに入力されたものを圧縮するストリーム、圧縮されたフォームを別のストリームに書き込むストリーム、またはデータを暗号化するストリームなどを持つことができます。もう一方の端には逆がありますチェーン、復号化、解凍など。
StreamReader
-またはそれ以上を取ると、TextReader
コードはデータフローの基礎となるストリームの種類を認識しません。または、BaseStream
プロパティを使用してタイプを見つけることができますが、コードがこれまでに見たことのないタイプである可能性があります。ポイントはあなたが気にするべきではないということです。そして、はい、あなたはすることができます絶対に時々ネットワークストリームのために使用され、時にはファイルストリームに使用するコードを書くに終わります。プロセスを介してデータをパイプ処理するストリームについては、プロセス内では行われません...ストリームプロバイダーです。
ストリームのポイントは、あなたとバッキングストアの間に抽象化の層を提供することです。したがって、バッキングストアがディスクファイルやメモリなどである場合、ストリームを使用する特定のコードブロックは気にする必要がありません。
エコーチャンバーに追加するために、ストリームは抽象化されているので、基になるストアを気にする必要はありません。ストリームがある場合とない場合のシナリオを検討する場合、これは最も理にかなっています。
ストリームは、私がよく知っている非ストリームベースのメソッドよりもはるかに優れているため、ファイルの大部分は興味をそそられません。インターネットファイルから始めましょう。
インターネットからファイルをダウンロードする場合は、TCPソケットを開いて接続を確立し、バイトがなくなるまでバイトを受信する必要があります。バッファを管理し、予期されるファイルのサイズを把握し、接続が切断されたことを検出して適切に処理するためのコードを記述する必要があります。
ある種のTcpDataStreamオブジェクトがあるとします。適切な接続情報を使用してそれを作成し、それからバイトがなくなるまでストリームからバイトを読み取ります。ストリームは、バッファ管理、データ終了条件、および接続管理を処理します。
このように、ストリームによりI / Oが容易になります。ストリームが行うことを実行するTcpFileDownloaderクラスを作成することもできますが、その場合はTCPに固有のクラスがあります。ほとんどのストリームインターフェイスは、Read()メソッドとWrite()メソッドを提供するだけで、より複雑な概念は内部実装によって処理されます。このため、同じ基本コードを使用して、メモリ、ディスクファイル、ソケット、およびその他の多くのデータストアの読み取りまたは書き込みを行うことができます。
私が使用している視覚化はコンベヤーベルトであり、それについて何も知らないため実際の工場ではありませんが、アイテムが線に沿って移動し、スタンプされ、箱に入れられ、一連のダムデバイスによってカウントおよびチェックされる漫画の工場では。
チェリーをケーキに載せるデバイスなど、1つのことを行う単純なコンポーネントがあります。このデバイスには、チェリーレスケーキの入力ストリームと、チェリーが入ったケーキの出力ストリームがあります。このように処理を構造化することに言及する価値のある3つの利点があります。
まず、コンポーネント自体が単純化されます。ケーキにチョコレートのアイシングをかけたい場合は、ケーキのすべてを知っている複雑なデバイスは必要ありません。チョコレートのアイシングをそこに供給されるものすべてに貼り付けるダムデバイスを作成できます。漫画の場合、これは次のアイテムがケーキではないことを知らない限り、ワイルE.コヨーテです)。
次に、デバイスを異なる順序で配置することで、さまざまな製品を作成できます。ケーキのアイシングの上にチェリーではなくアイチェリーの上にアイシングを配置したい場合があります。これは、デバイスをライン上で交換するだけで実行できます。 。
第3に、デバイスは在庫、ボックス化、ボックス化解除を管理する必要がありません。物事を集約してパッケージ化する最も効率的な方法は変更可能です。たぶん、今日あなたはケーキを48箱に入れてトラック積みで送りますが、明日はカスタム注文に応じて6箱を送りたいと考えています。この種の変更は、生産ラインの最初と最後でマシンを交換または再構成することで対応できます。ラインの真ん中にある桜のマシンは、一度に異なる数のアイテムを処理するために変更する必要はありません。常に一度に1つのアイテムで動作し、その入力または出力がどのようであるかを知る必要はありません。グループ化されています。
初めてストリーミングについて聞いたとき、それはウェブカメラによるライブストリーミングのコンテキストでした。つまり、1つのホストがビデオコンテンツをブロードキャストし、もう1つのホストがビデオコンテンツを受信しています。これはストリーミングですか?ええと...はい...しかし、ライブストリームは具体的な概念であり、質問はストリーミングの抽象的な概念を参照していると思います。https://en.wikipedia.org/wiki/Live_streamingを参照してください
それでは次に進みましょう。
ストリーミングできるのはビデオだけではありません。オーディオもストリーミングできます。それでは、ストリーミングメディアについてお話します。https://en.wikipedia.org/wiki/Streaming_mediaを参照してください。オーディオは、さまざまな方法でソースからターゲットに配信できます。それでは、いくつかのデータ配信方法を互いに比較してみましょう。
クラシックファイルのダウンロード クラシックファイルのダウンロードはリアルタイムでは発生しません。ファイルを使用する前に、ダウンロードが完了するまで待つ必要があります。
プログレッシブダウンロード プログレッシブダウンロードチャンクは、ストリーミングメディアファイルから一時バッファーにデータをダウンロードします。そのバッファー内のデータは動作可能です。バッファー内のオーディオビデオデータは再生可能です。そのため、ユーザーはダウンロード中にストリーミングメディアファイルを視聴できます。もちろん、バッファを使って早送りや巻き戻しも可能です。とにかく、プログレッシブダウンロードはライブストリーミングではありません。
ストリーミングは リアルタイムで発生し、データをチャンクします。ストリーミングはライブブロードキャストで実装されます。ブロードキャストを聞いているクライアントは、早送りや巻き戻しはできません。ビデオストリームでは、データは再生後に破棄されます。
ストリーミングサーバーはクライアントとの双方向接続を維持し、Webサーバーはサーバーの応答後に接続を閉じます。
ストリーミングできるのはオーディオとビデオだけではありません。PHPマニュアルでストリームの概念を見てみましょう。
ストリームは、ストリーミング可能な動作を示すリソースオブジェクトです。すなわち、それはすることが可能であるから読み出しまたはに書き込まれたストリーム内の任意の場所に)直線的に、かつ(FSEEKすることができるかもしれません。リンク:https : //www.php.net/manual/en/intro.stream.php
PHPでは、リソースはファイルやデータベース接続などの外部ソースへの参照です。つまり、言い換えれば、ストリームは読み取りまたは書き込みが可能なソースです。したがって、で作業した場合はfopen()
、すでにストリームで作業しています。
ストリーミングの対象となるテキストファイルの例:
// 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ファイルもストリーミングできます。その上、ストリーミングはファイルに限定されません。HTTP、FTP、SSH接続、および入出力もストリーミングできます。
ウィキペディアはストリーミングの概念について何と言っていますか?
コンピュータサイエンスでは、ストリームは時間の経過とともに利用可能になる一連のデータ要素です。ストリームは、大量のバッチではなく、一度に1つずつ処理されるコンベヤベルト上のアイテムと考えることができます。
参照:https : //en.wikipedia.org/wiki/Stream_%28computing%29。
これにウィキペディアリンク:https://srfi.schemers.org/srfi-41/srfi-41.html や作家が流れについて言うためにこれを持っています:
ストリームは、遅延リストと呼ばれることもあり、オンデマンドでのみ計算される要素を含む順次データ構造です。ストリームはnullであるか、cdr内のストリームとペアになっています。ストリームの要素はアクセス時にのみ計算されるため、ストリームは無限になり得ます。
したがって、ストリームは実際にはデータ構造です。
私の結論:ストリームは、シーケンシャルな方法で読み書きできるデータを含むことができるソースです。ストリームは、ソースに含まれるすべてを一度に読み取るのではなく、順次読み取り/書き込みを行います。
役立つリンク:
これは単なる概念であり、人生を楽にする抽象化のもう1つのレベルです。そして、それらすべてに共通のインターフェースがあり、パイプのようにそれらを組み合わせることができます。たとえば、base64にエンコードしてからzipで圧縮し、これをディスクに書き込んで、すべて1行で書きます
私が見たストリームの最も良い説明は、SICPの第3章です。(それを理解するために最初の2つの章を読む必要があるかもしれませんが、とにかくあなたはそうすべきです。:-)
バイトにはステラムをまったく使用せず、整数を使用します。私がそれから得た大きな点は次のとおりです。
バッキングストア自体は、多くの場合、単なる別の抽象概念であると考える必要があると思います。メモリストリームは非常に理解しやすいですが、ファイルは使用しているファイルシステムによって根本的に異なります。使用しているハードドライブを気にしないでください。すべてのストリームが実際にバッキングストアの上にあるわけではありません。ネットワークストリームは、ほとんどがストリームです。
ストリームのポイントは、重要なことに注意を向けることです。標準の抽象化を行うことにより、一般的な操作を実行できます。たとえば、今日ファイルまたはHTTP応答でURLを検索したくない場合でも、明日は望まないというわけではありません。
ストリームは、もともとメモリがストレージと比較して小さいときに考案されました。Cファイルを読み取るだけでは、かなりの負荷になる可能性があります。メモリフットプリントを最小限に抑えることが非常に重要でした。したがって、ロードする必要がほとんどない抽象化は非常に有用でした。今日では、ネットワーク通信を実行するときにも同様に便利ですが、ファイルを処理するときに制限が生じることはめったにありません。一般的な方法でバッファリングのようなものを透過的に追加する機能は、それをさらに便利にします。
ストリームは、データと対話するためのメソッドとプロパティの標準セットを提供する抽象概念です。実際のストレージメディアから抽象化することで、そのメディアが何であるか、またはそのメディアの実装にまったく依存することなく、コードを記述できます。
良い例えはバッグを考えることかもしれません。バッグがバッグの役目を果たし、アイテムを取り戻すことができる限り、バッグの素材やアイテムを入れたときに何が起こるかは気になりません。ストリームは、バッグの概念がバッグのさまざまなインスタンス(ゴミ袋、ハンドバッグ、リュックサックなど)に対して定義するものをストレージメディアに定義します-相互作用のルール。