コンテンツにスキップ

「ストリーム (プログラミング)」の版間の差分

出典: フリー百科事典『ウィキペディア(Wikipedia)』
削除された内容 追加された内容
Nallimbot (会話 | 投稿記録)
m ロボットによる 追加: ko:스트림 (컴퓨터) 変更: ru:Поток данных
m編集の要約なし
 
(22人の利用者による、間の32版が非表示)
1行目: 1行目:
{{出典の明記|date=2024年2月}}
'''ストリーム'''(stream)とは、データの入力または出力の機能を提供する[[抽象データ型]]である。ファイルの入出力を扱うもの、[[メモリバッファ]]の入出力を扱うもの、ネットワーク通信を扱うものなどさまざまなものがある。
'''ストリーム'''({{lang-en-short|stream}})とは、データを、比較的小さい単位が連続したものと捉え、上流から下流へ「流れるもの」とみなし、そのデータの入出力・送受信(途中段階を含む)を最小限の滞留とさせ低遅延処理となるように扱う形態を指す。またその操作のための[[抽象データ型]]を指す<ref>[http://e-words.jp/w/%E3%82%B9%E3%83%88%E3%83%AA%E3%83%BC%E3%83%A0.html ストリームとは - IT用語辞典 e-Words]</ref>。

処理内部では適切なデータ分割・[[バッファリング]]が行われる。

入力ストリーム (input stream) を利用してデータの読み出しを行ない、出力ストリーム (output stream) を利用してデータの書き込みを行なう。対照的な概念としては、保管・永続化されたデータ形態([[ファイル (コンピュータ)|ファイル]]、[[データベース]]など)がある。

[[メモリバッファ]]の入出力を扱うもの、ネットワーク通信を扱うものなどさまざまなものがある。ファイルの入出力(読み書き)に対しては、ストリームとの変換を行う仕組みが用意される。

典型例として、[[Unix]][[オペレーティングシステム]]およびその[[シェル]]によって実装されたものがある([[標準ストリーム]]、[[パイプ (コンピュータ)|パイプライン]]、[[リダイレクト (CLI)|リダイレクト]])<ref>ただしxargsコマンドで-Pオプションを指定し[[並列処理]]させた場合の実行コマンドの標準出力は[[バッファリング]]が働かず混合が生じる。</ref>。

== 標準ストリーム ==
{{main|標準ストリーム}}
[[オペレーティングシステム]](例えば[[Unix]])の標準的な入力元や出力先に対して、[[標準ストリーム]]と呼ばれる特別なストリームが用意される。

[[キーボード (コンピュータ)|キーボード]]からの入力、[[ディスプレイ (コンピュータ)|ディスプレイ]]への出力も、標準ストリームによって抽象化され、個別のプログラムからはデバイスハードウェアを意識する必要がなくなる。

== C言語 ==
[[C言語]]では[[Unix]]由来の標準ストリームとして、標準入力<code>stdin</code>、標準出力<code>stdout</code>、標準エラー出力<code>stderr</code>が定義されている。これらはすべてファイルストリームとして抽象化されており、ファイルポインタ<code>FILE*</code>のひとつとして扱うことができる。[[標準Cライブラリ]]の[[ヘッダーファイル]]<code><nowiki><stdio.h></nowiki></code>において、ストリームを扱う[[サブルーチン|関数]]が定義されている。例えば[[printf]]関数は標準出力への書き込みを、[[scanf]]関数は標準入力からの読み出しを行なう。


==C++==
==C++==
===入出力ストリーム===
===入出力ストリーム===
<tt><iostream></tt>[[ヘッダファイル]]標準入出力ストリームとして<tt>cout</tt>、<tt>cin</tt>、<tt>cerr</tt>、<tt>clog</tt>、およびワイド文字列用<tt>wcout</tt>、<tt>wcin</tt>、<tt>wcerr</tt>、<tt>wclog</tt>が定義されている。
[[C++]]では、[[標準C++ライブラリ]]のヘッダファイル<code><iostream></code>おいて、標準入出力ストリームとして<code>cin</code>、<code>cout</code>、<code>cerr</code>、<code>clog</code>が定義されている。[[ワイド文字]]列用には別途<code>wcin</code>、<code>wcout</code>、<code>wcerr</code>、<code>wclog</code>が定義されている。


<source lang="cpp">
<syntaxhighlight lang="cpp">
#include <iostream>
#include <iostream>
int main()
int main()
12行目: 30行目:
return 0;
return 0;
}
}
</syntaxhighlight>
</source>


C++は強く型付けされた言語であるが、この標準入出力ストリームは[[多重定義]]によって全く型を意識せずに入出力を行える。さらにユーザー定義型も多重定義により定義できるため、非常に柔軟な入出力が可能である。さらに入出力操作子(マニピュレータ)の導入により、細かな制御が可能となった。
C++は強く型付けされた言語であるが、この標準入出力ストリームは[[多重定義]]によって全く型を意識せずに入出力を行える。特定の演算子を多重定義したユーザー定義型([[クラス (コンピュータ)|クラス]]あるいは[[構造体]])利用できるため、非常に柔軟な入出力が可能である。さらに入出力操作子(マニピュレータ)の導入により、細かな制御が可能となった。


<source lang="cpp">
<syntaxhighlight lang="cpp">
#include <iostream>
#include <iomanip>
...
int i;
int i;
std::string s;
std::string s;
23行目: 44行目:
std::cin >> std::setw(10) >> s; // 10文字読み込む。
std::cin >> std::setw(10) >> s; // 10文字読み込む。
std::cin >> d; // オーバーロードすることで任意のデータをdに読み込む。
std::cin >> d; // オーバーロードすることで任意のデータをdに読み込む。
</syntaxhighlight>
</source>


これらの機能により、従来の<tt>[[printf]]</tt>関数で起こりがちであった型の不一致や制御子の過不足によるバグの可能性がきわめて低くなった。しかしその半面、マニピュレータの仕様など覚えなければならないが増加し、またタイプ数も<tt>printf</tt>と比べ格段に増えてしまったため、敬遠するプログラマも多い。
これらの機能により、従来の型消去 (type erasure) や型昇格 (type promotion) を伴う[[可変長引数]]を利用した<code>printf</code>関数で起こりがちであった型の不一致や制御子の過不足によるバグの可能性がきわめて低くなった。しかしその半面、マニピュレータの仕様など覚えなければならないことが増加し、また記述量も<code>printf</code>と比べ格段に増えてしまったため、敬遠するプログラマも多い。


===文字列ストリーム===
===文字列ストリーム===
<tt><sstream></tt>ヘッダファイルには文字列を対象としたストリーム操作の機能を提供するクラス<tt>istringstream</tt>、<tt>ostringstream</tt>が定義されている。
標準ヘッダーのひとつ<code><sstream></code>には文字列を対象としたストリーム操作の機能を提供するクラス<code>istringstream</code>、<code>ostringstream</code>が定義されている。

=== 外部ライブラリ ===
[[Boost C++ライブラリ]]における<code>boost::format</code>は[[型システム|型安全]]な<code>sprintf()</code>であり、出力の際のマニピュレータの記述の煩雑さを軽減する。

== Javascript ==
{{main|JavaScript}}
ストリーム API<ref>参考: https://triple-underscore.github.io/Streams-ja.html</ref>を持つ([[WHATWG]]により策定が進められている)。

== Node.js ==
{{main|Node.js}}
ストリームを扱うモジュールを持つ。

== Java ==
{{main|Java}}
ストリーム API を持つ。


==.NET Framework==
==.NET Framework==
[[.NET Framework]]でも入出力をストリームに一般化しており、ここでは低水準な<code>Read</code>, <code>Write</code>メソッドのみサポートしている。以下に代表的なクラスを挙げる。
;<tt>System.IO.Stream</tt>
;<code>System.IO.Stream</code>
:一般的なストリームのインターフェスを提供する抽象クラス。
:一般的なストリームのインターフェスを提供する[[抽象クラス]]
;<tt>System.IO.FileStream</tt>
;<code>System.IO.FileStream</code>
:ファイル入出力機能を提供するストリーム。
:ファイル入出力機能を提供するストリーム。
;<tt>System.IO.MemoryStream</tt>
;<code>System.IO.MemoryStream</code>
:メモリバッファの入出力機能を提供するストリーム。
:[[メモリバッファ]]の入出力機能を提供するストリーム。
;<tt>System.Net.Sockets.NetworkStream</tt>
;<code>System.Net.Sockets.NetworkStream</code>
:ネットワークの入出力機能を提供するストリーム。
:ネットワークの入出力機能を提供するストリーム。

;<tt>System.IO.BinaryWriter / System.IO.BinaryReader</tt>
上記のストリームを読み書きするためのクラスが別途存在し、通常はこれらを用いて入出力処理を行なう。
;<code>System.IO.BinaryWriter</code> / <code>System.IO.BinaryReader</code>
:ストリームに対してバイナリ形式での読み書き機能を提供するクラス。
:ストリームに対してバイナリ形式での読み書き機能を提供するクラス。
;<tt>System.IO.TextWriter / System.IO.TextReader</tt>
;<code>System.IO.TextWriter</code> / <code>System.IO.TextReader</code>
:ストリームに対してテキスト形式での読み書き機能を提供するクラス。
:ストリームに対してテキスト形式での読み書き機能を提供するクラス。
;<tt>System.IO.BufferedStream</tt>
;<code>System.IO.BufferedStream</code>
:既存のストリームにバッファリング機能を追加するためのストリーム。
:既存のストリームに[[バッファリング]]機能を追加するためのストリーム。

== 関数型言語 ==
[[関数型言語]]においては専ら、無限の大きさ(長さ、要素数)の[[再帰|再帰的]]なデータ構造を指す。[[遅延評価]]を用いて実装されるため「遅延ストリーム」とも呼ばれる。無限のデータを扱うには、そのうちの一部を切り出したりする関数も必要なほか、ストリームを成すデータも再帰関数によって生成されるため、[[オブジェクト指向]]の関数型言語では、これらをまとめてストリームクラスとして実装することもある。関数が出力するストリーム自体は[[連結リスト]]として実装されることが多い。

遅延評価は必要なときに必要なだけ関数を評価し、不要になったら関数の評価を正常に中断することができる。このことは[[再帰#再帰呼出し|再帰呼び出し]]を中断する条件(停止条件)の判定を一切行わない再帰関数や再帰的な値の定義を可能にする。たとえば[[階乗]]を求める関数は、1から順に再帰的にかけ算してその結果を返すよう定義するだけである。上限などを設ける必要はなく、かわりに「結果をn個求めてリストにする」関数や「結果をx個捨てる」関数などを介して呼び出す。条件判定をしないということは、遅延評価を行わない言語では[[無限ループ]]に陥いるということである。しかしそのような言語でも無限の要素数を持つデータを扱えるようにするため、ストリームに関してだけ遅延評価を取り入れている。

無限に再帰する関数や値から一部を取り出したりするしくみは巧妙にできている。「結果をn回求める」関数をrepeat、再帰関数をrecとしてその経過を見る。
# repeatがrecを1度だけ呼び出す
# recは再帰する直前の状態で一旦結果を返す
# repeatは結果とともに、recを1回分だけ評価された関数(サンク。[[クロージャ]]の一種)として受け取りリストに連結する
# recを呼び出した回数がnでないなら、recをサンクの状態からフォース(強制評価)する
# 2から4を繰り返す
# recの結果を返す

サンクは関数を評価した途中経過と見做せる。recを階乗関数factとして3回評価する場合のサンクの状態を(概念的にだが)示す。
fact関数は<code> fact i = i * (fact i+1) </code>と定義すればよい。
# repeat 3 (fact 1)
# repeat 3 (1 * fact 1+1)
# repeat 3 (1 * 2 * fact 2+1)
# repeat 3 (1 * 2 * 3 * fact 3+1)
# ---> 6
カッコの中全体がサンクと言える。また、フォースは「カッコの中と関数をひとつの関数として呼び出すこと」と言える。

遅延評価が標準である言語ではすべての再帰的な定義がストリームのように機能するため、とくにストリームと呼ぶことはない。しかし[[Haskell]]においては、[[モナド (プログラミング)|モナド]]が導入される以前は、[[参照透過性|参照透過]]な入出力を実現するためのデータ構造をストリームと呼んでいた。

== 脚注 ==
{{Reflist}}


==関連項目==
==関連項目==
* [[C++]]
* [[標準ストリーム]]
* [[Boost]] - <tt>boost::format</tt>は安全な<tt>sprintf()</tt>であり、出力の際のマニピュレータの煩雑さを軽減する。
* [[入出力]]
* [[入出力]]
* [[ストリーム・プロセッシング]]
* [[ストリーム・プロセッシング]]
* [[ストリーミング]]


[[Category:コンピュータのデータ|すとりいむ]]
{{DEFAULTSORT:すとりいむ}}
[[Category:情報処理|すとりいむ]]
[[Category:コンピュータのデータ]]
[[Category:C++|すとりいむ]]
[[Category:情報処理]]
[[Category:データ型|すとりいむ]]
[[Category:C++]]
[[Category:.NET]]

[[Category:データ型]]
[[en:Stream (computing)]]
[[Category:ビジネスアナリシス]]
[[ko:스트림 (컴퓨터)]]
[[pt:Stream]]
[[ru:Поток данных]]

2024年2月16日 (金) 13:57時点における最新版

ストリーム: stream)とは、データを、比較的小さい単位が連続したものと捉え、上流から下流へ「流れるもの」とみなし、そのデータの入出力・送受信(途中段階を含む)を最小限の滞留とさせ低遅延処理となるように扱う形態を指す。またその操作のための抽象データ型を指す[1]

処理内部では適切なデータ分割・バッファリングが行われる。

入力ストリーム (input stream) を利用してデータの読み出しを行ない、出力ストリーム (output stream) を利用してデータの書き込みを行なう。対照的な概念としては、保管・永続化されたデータ形態(ファイルデータベースなど)がある。

メモリバッファの入出力を扱うもの、ネットワーク通信を扱うものなどさまざまなものがある。ファイルの入出力(読み書き)に対しては、ストリームとの変換を行う仕組みが用意される。

典型例として、Unixオペレーティングシステムおよびそのシェルによって実装されたものがある(標準ストリームパイプラインリダイレクト[2]

標準ストリーム

[編集]

オペレーティングシステム(例えばUnix)の標準的な入力元や出力先に対して、標準ストリームと呼ばれる特別なストリームが用意される。

キーボードからの入力、ディスプレイへの出力も、標準ストリームによって抽象化され、個別のプログラムからはデバイスハードウェアを意識する必要がなくなる。

C言語

[編集]

C言語ではUnix由来の標準ストリームとして、標準入力stdin、標準出力stdout、標準エラー出力stderrが定義されている。これらはすべてファイルストリームとして抽象化されており、ファイルポインタFILE*のひとつとして扱うことができる。標準Cライブラリヘッダーファイル<stdio.h>において、ストリームを扱う関数が定義されている。例えばprintf関数は標準出力への書き込みを、scanf関数は標準入力からの読み出しを行なう。

C++

[編集]

入出力ストリーム

[編集]

C++では、標準C++ライブラリのヘッダーファイル<iostream>において、標準入出力ストリームとしてcincoutcerrclogが定義されている。ワイド文字列用には別途wcinwcoutwcerrwclogが定義されている。

#include <iostream>
int main()
{
    std::cout << "Hello, World!" << std::endl;
    return 0;
}

C++は強く型付けされた言語であるが、この標準入出力ストリームは多重定義によって全く型を意識せずに入出力を行なえる。特定の演算子を多重定義したユーザー定義型(クラスあるいは構造体)も利用できるため、非常に柔軟な入出力が可能である。さらに入出力操作子(マニピュレータ)の導入により、細かな制御が可能となった。

#include <iostream>
#include <iomanip>
...
int i;
std::string s;
my_data_type d;
std::cin >> i; // 整数の入力をiに読み込む。
std::cin >> std::setw(10) >> s; // 10文字読み込む。
std::cin >> d; // オーバーロードすることで任意のデータをdに読み込む。

これらの機能により、従来の型消去 (type erasure) や型昇格 (type promotion) を伴う可変長引数を利用したprintf関数で起こりがちであった、型の不一致や制御子の過不足によるバグの可能性がきわめて低くなった。しかしその半面、マニピュレータの仕様など覚えなければならないことが増加し、また記述量もprintfと比べ格段に増えてしまったため、敬遠するプログラマも多い。

文字列ストリーム

[編集]

標準ヘッダーのひとつ<sstream>には、文字列を対象としたストリーム操作の機能を提供するクラスistringstreamostringstreamが定義されている。

外部ライブラリ

[編集]

Boost C++ライブラリにおけるboost::format型安全sprintf()であり、出力の際のマニピュレータの記述の煩雑さを軽減する。

Javascript

[編集]

ストリーム API[3]を持つ(WHATWGにより策定が進められている)。

Node.js

[編集]

ストリームを扱うモジュールを持つ。

Java

[編集]

ストリーム API を持つ。

.NET Framework

[編集]

.NET Frameworkでも入出力をストリームに一般化しており、ここでは低水準なLesen, Writeメソッドのみサポートしている。以下に代表的なクラスを挙げる。

System.IO.Stream
一般的なストリームのインターフェイスを提供する抽象クラス
System.IO.FileStream
ファイル入出力機能を提供するストリーム。
System.IO.MemoryStream
メモリバッファの入出力機能を提供するストリーム。
System.Net.Sockets.NetworkStream
ネットワークの入出力機能を提供するストリーム。

上記のストリームを読み書きするためのクラスが別途存在し、通常はこれらを用いて入出力処理を行なう。

System.IO.BinaryWriter / System.IO.BinaryReader
ストリームに対してバイナリ形式での読み書き機能を提供するクラス。
System.IO.TextWriter / System.IO.TextReader
ストリームに対してテキスト形式での読み書き機能を提供するクラス。
System.IO.BufferedStream
既存のストリームにバッファリング機能を追加するためのストリーム。

関数型言語

[編集]

関数型言語においては専ら、無限の大きさ(長さ、要素数)の再帰的なデータ構造を指す。遅延評価を用いて実装されるため「遅延ストリーム」とも呼ばれる。無限のデータを扱うには、そのうちの一部を切り出したりする関数も必要なほか、ストリームを成すデータも再帰関数によって生成されるため、オブジェクト指向の関数型言語では、これらをまとめてストリームクラスとして実装することもある。関数が出力するストリーム自体は連結リストとして実装されることが多い。

遅延評価は必要なときに必要なだけ関数を評価し、不要になったら関数の評価を正常に中断することができる。このことは再帰呼び出しを中断する条件(停止条件)の判定を一切行わない再帰関数や再帰的な値の定義を可能にする。たとえば階乗を求める関数は、1から順に再帰的にかけ算してその結果を返すよう定義するだけである。上限などを設ける必要はなく、かわりに「結果をn個求めてリストにする」関数や「結果をx個捨てる」関数などを介して呼び出す。条件判定をしないということは、遅延評価を行わない言語では無限ループに陥いるということである。しかしそのような言語でも無限の要素数を持つデータを扱えるようにするため、ストリームに関してだけ遅延評価を取り入れている。

無限に再帰する関数や値から一部を取り出したりするしくみは巧妙にできている。「結果をn回求める」関数をrepeat、再帰関数をrecとしてその経過を見る。

  1. repeatがrecを1度だけ呼び出す
  2. recは再帰する直前の状態で一旦結果を返す
  3. repeatは結果とともに、recを1回分だけ評価された関数(サンク。クロージャの一種)として受け取りリストに連結する
  4. recを呼び出した回数がnでないなら、recをサンクの状態からフォース(強制評価)する
  5. 2から4を繰り返す
  6. recの結果を返す

サンクは関数を評価した途中経過と見做せる。recを階乗関数factとして3回評価する場合のサンクの状態を(概念的にだが)示す。 fact関数は fact i = i * (fact i+1) と定義すればよい。

  1. repeat 3 (fact 1)
  2. repeat 3 (1 * fact 1+1)
  3. repeat 3 (1 * 2 * fact 2+1)
  4. repeat 3 (1 * 2 * 3 * fact 3+1)
  5. ---> 6

カッコの中全体がサンクと言える。また、フォースは「カッコの中と関数をひとつの関数として呼び出すこと」と言える。

遅延評価が標準である言語ではすべての再帰的な定義がストリームのように機能するため、とくにストリームと呼ぶことはない。しかしHaskellにおいては、モナドが導入される以前は、参照透過な入出力を実現するためのデータ構造をストリームと呼んでいた。

脚注

[編集]
  1. ^ ストリームとは - IT用語辞典 e-Words
  2. ^ ただしxargsコマンドで-Pオプションを指定し並列処理させた場合の実行コマンドの標準出力はバッファリングが働かず混合が生じる。
  3. ^ 参考: https://triple-underscore.github.io/Streams-ja.html

関連項目

[編集]