こんにちは、このコースでは ストリームライブラリについてお話します。
ストリームは Pharo の 基本的な特徴の1つです。
ストリームが何で、どう使うか、 いつ使うと便利かを見ていきましょう。
ストリームとは何でしょう？
ストリームオブジェクトは
コレクションのような要素列を
列挙することを可能にします。
この要素列はメモリ中のコレクション かもしれませんし
ネットワークから流れてくるかもしれませんし ファイル等かもしれません。
ストリームはメモリ中に 現在位置を保持します。
ストリームを使う時には 前に進めたり戻ったりしながら
ストリームを読んだり書いたりします。
ストリームの API の全体図です。
ストリームを作るためには いくつかのオブジェクトは
readStream や writeStream というメッセージを使って
ストリームを作ることができます。
（例えば、ファイルやコレクションから）
こうしてストリームを作ることができます。
この streamContents: メッセージが Collection に送られて
ブロックが引数として渡されます。 ブロックはストリームを受け取ります。
このブロックの中でストリームを使って コレクションを作ります。
streamContents: メソッドが そのコレクションを返します。
このメソッドの使い方は 終わりのほうで見ることになります。
この場合は、
readStream か writeStream か ReadWriteStream クラスに直接たのんで
コレクション上に新しいインスタンスを作ります。
これらの 3 つのメソッドは 要素を 1 つ読んだり
あるところまで複数読んだりします。
これらの 2 つは
要素を 1 つか、または要素のコレクションを ストリームに書き込みます。
ストリームから読み込み例がいくつかあります。
まず、ストリームを作ります。
コレクションから readStream を作ります。
コレクションには a から f までの 全ての文字が入っています。
コレクションの各要素として 1つずつの文字が入っています。
コレクション上のストリームを作ります。 1つ1つの文字を見ていきましょう。
ストリームの準備ができたら
最初に next メッセージを送ります。
ストリームが初期化された現在位置から
要素を返します。
ストリームの現在位置は 0 で ストリームの先頭位置です。
next は最初の要素である a を返します。
ここで next を呼ぶと
b が得られて、そして c となります。 1つずつ。
next を呼ぶことで 現在位置が1つずつ移動します。
next を呼んで a を得てから
upTo: メッセージを送って 引数として要素を1つ渡します。
このメソッドは現在位置から 引数として渡した要素までの
全ての要素を返します。
現在位置が 1 で、a が得られた状態で
upTo: $d を送ると
現在位置から d までのものを返します。
b と c です。
d はストリームから取り出されています。
つまり、ストリームの現在位置は d の後になっています。
d は返されていません。
stream position は現在位置を返します。
現在位置は 0 で始まります。
0 は最初の要素の前にあります。 0、1、2、3、4、と。
現在 e の前で d の後になっています。
ここで upToEnd メッセージをストリームに送ると 現在位置からストリームの末尾までの
全ての要素を得ることができます。
e と f です。
ストリームが管理している現在位置を いくつかのメソッドを使って
進めることができます。
ストリームに書き込むこともできます。
最初に、ストリームを作ります。
Array new: 6 で 大きさ 6 の配列を作ります。
writeStream メッセージを送って その配列上にストリームを作って
ストリームを使って配列の中身を 徐々に埋めていくことができます。
変数 stream にストリームを格納します。
最初に nextPut: 1 メッセージを送ります。
引数を 1 つ取って ストリームの現在位置にそれを追加します。
配列には現在 1 が入っていて 空のセルが 5 個続いています。
nextPutAll: メッセージは コレクションオブジェクトを取って
ストリームに連結します。
ストリームに nextPutAll: メッセージを送ると
配列には、前回の nextPut: の結果の
1 が入っていて
nextPutAll: の結果の
4 8 2 6 7 が続きます。
ストリームはオブジェクトのコレクションの
読み書きをする上で 特に便利で効率的です。
ファイルに読み書きをすることもできます。
例として
新規ファイルに書き込む方法を示します。
ストリームでは ファイルの名前を入力します。
asFilereference メッセージを送ることで
ファイルへの参照を作ります。
これはまだ存在しないファイルですが そのファイルへの参照を得ることができます。
hello.txt ファイルへの参照が得られました。
そのファイルにwriteStream メッセージを
送ることで
このまだ存在しないファイルに関連つけられた 書き込み用のストリームが得られます。
このストリームに書き込むと すぐにファイルが作られます。
ここでストリームがあって nextPutAll:メッセージを文字列をつけて送ります。
このメッセージは文字列の各要素を 1つずつ書き込んでいきます。
h 次に e 次に l、という具合です。
最後に
ストリームを閉じることで
ファイルへの書き込みが終わり
ストレージに全て書き出してしまって
ファイルポインタを閉じて良い ということを OS に伝えます。
これでファイルに書き込みました。 それを読み込むことができます。
ファイル名を
文字列として示して
asFileReference で このファイルへの参照を作ります。
readStream で
読み込みモードで開いて
読み込み用ストリームを作ります。
next で、ストリームの最初の要素を得ます。
「Hello Pharo!」と書き込んだので 最初の要素は H です。
現在位置は H の後で e の前ですが
upToEnd でその現在位置から
ファイルの終わりまでの要素を得ます。
H 抜きの 「ello Pharo!」が得られます。
H は next で既に取り出しているので。
ストリームを使って コレクションを作ることができます。
コレクションを作って
中に何がはいるべきかを 徐々に選んでいきたい時に便利です。
OrderedCollection を
ストリームにメッセージを送ることで 作ります。
OrderedCollection の
新しいインスタンスから始めて
writeStream にします。
nextPut: メッセージで ストリームに 1 を加えます。
stream contents で
値 1 だけが格納された
OrderedCollection クラスの インスタンスが得られます。
これら3つの式は下に示したように 簡略化できます。
streamContents: メッセージを
欲しいコレクションのクラスである OrderedCollection に送ります。
OrderedCollection に streamContents: を送り
引数としてブロックを渡します。 ブロックは引数としてストリームを受け取ります。
ブロックでは、コレクションの中身を ストリームを使って徐々に埋めていきます。
ブロックが終わったら コレクションが得られます。
ブロックでは、stream nextPut: 1 としています。
ストリームに 1 を加えます。
1 がコレクションに追加されます。
この表現式が終わると streamContents: が終了します。
1 を格納した OrderedCollection が得られます。
streamContents: はコレクションを 真っ新な状態から作るときに便利です。
このコースでは ストリームの API を学びました。
Nautilus コードナビゲーターで クラスを探索して
学ぶべきメソッドが沢山あります。
ストリームでメモリ上のコレクションや ファイルやネットワークなどを
読んだり書いたりすることができます。
ストリームは現在位置を管理します。
現在位置は 過去の要素と未来の要素の区切りです。
ストリームを読み書きする度に 現在位置が変化します。
ストリームは新しいコレクションを作る のにも役に立ちます。