SophiaFramework UNIVERSE 5.3 |
ストリームは、内部バッファ(以下、バッファ)を使用してストレージのデータを読み書きします。
バッファには、サイズが固定長であるものと可変長であるものの 2 種類が存在します。 可変長であるストリームを『可変長バッファストリーム』、 固定であるものを『固定長バッファストリーム』と呼びます。
表 17.6. 固定長バッファストリームと可変長バッファストリーム
項目 | 固定長バッファストリーム | 可変長バッファストリーム |
---|---|---|
特徴 | バッファのサイズは固定 | バッファのサイズは読み書きするデータに合わせて可変 |
取得方法(設定方法) | GetStreamReader / GetStreamWriter 関数の size 引数にバッファのサイズを指定する | GetStreamReader / GetStreamWriter 関数の size 引数を指定しない |
読み書きの方法 | バッファのサイズよりも大きなデータは複数回に分けてストリームに読み書きする | 1 回のストリームへの読み書き操作でデータ読み書きが完了する |
Tip | |
---|---|
可変長バッファストリームのバッファは、 ストレージから読み込んだり、 書き込んだりするデータに応じて自動的に拡張されます。 メモリを節約したい場合、あるいは、データサイズが予測できない場合は、 固定長バッファストリームを利用して複数回に分けてデータを読み書きします。 |
SFXElasticStreamReader / SFXElasticStreamWriter クラス | |
---|---|
可変長バッファストリーム経由のデータ読み書きは、 内部的に SFXElasticStreamReader / SFXElasticStreamWriter クラスで行われますが、 開発者はこのクラスについて意識する必要はありません。 |
可変長バッファストリームとは、 読み書きするデータ合わせてバッファのサイズが自動的に拡張されるストリームのことです。
すべてのデータがバッファに格納されるのでストリームに 1 回の操作で読み書きは完了します。
可変長バッファストリームは、size 引数を指定せずにストレージクラスの GetStreamReader / GetStreamWriter 関数を呼び出すことにより取得できます。
例 17.22. 可変長バッファストリームによるファイル入力
SFXFile file; // ファイル SFXAnsiStringStreamReader reader; // ファイル読み込み用ストリーム SFXAnsiString string; // 読み込む文字列 // 読み込みモードでファイルを開く if ((error = file.OpenReadOnly(SFXPath("/dir/data.txt"))) == SFERR_NO_ERROR) { // ファイル読み込み用ストリームを取得する // ※ size 引数を指定していないのでストリームバッファは可変長 if ((error = file.GetStreamReader(&reader)) == SFERR_NO_ERROR) { // ファイルからストリームバッファにデータを読み込む // ※1. 読み込んだデータのサイズに合わせてストリームバッファは自動的に拡張される // ※2. 可変長バッファストリームの場合、1 回の Fetch 関数呼び出しで読み込みは完了する if ((error = reader.Fetch()) == SFERR_NO_ERROR) { // ストリームバッファから string 変数にデータを読み込む if ((error = reader.ReadSFXAnsiString(&string)) == SFERR_NO_ERROR) { // ファイル読み込み成功! // string 変数の内容をデバッグウィンドウに表示する TRACE("%s", string.GetCString()); } } // ファイル読み込み用ストリームを解放する reader.Release(); } // ファイルを閉じる file.Close(); } if (error != SFERR_NO_ERROR) { // エラーが発生したとき ... }
可変長バッファストリームによるファイル読み込み | |
---|---|
ストリームにはバッファがあります。 SFXFile::GetStreamReader 関数で size 引数を指定せずにファイル読み込み用ストリームを取得しているので、 可変長バッファが使用されます。 このため、 ストリームバッファは入力ファイルと同じサイズまで拡張されます。 SFXStreamReader::Fetch 関数は、 ファイルからデータを読み込み、ストリームバッファに読み込みます。 SFXAnsiStringStreamReader::ReadSFXAnsiString 関数は、 ストリームバッファからデータを読み込み、string 変数に格納します。 |
例 17.23. 可変長バッファストリームによるファイル出力
SFXFile file; // ファイル SFXAnsiStringStreamWriter writer; // ファイル書き込み用ストリーム SFXAnsiString string("abcdefg"); // 書き込む文字列 // 読み書きモードでファイルを開く if ((error = file.OpenReadWrite(SFXPath("/dir/data.txt"))) == SFERR_NO_ERROR) { // ファイル書き込み用ストリームを取得する // ※ size 引数を指定していないのでストリームバッファは可変長 if ((error = file.GetStreamWriter(&writer)) == SFERR_NO_ERROR) { // string 変数からストリームバッファにデータを書き込む // ※ 書き込んだデータのサイズに合わせてストリームバッファは自動的に拡張される if ((error = writer.WriteSFXAnsiString(string)) == SFERR_NO_ERROR) { // ストリームバッファからファイルにデータを書き込む // ※ 可変長バッファストリームの場合、1 回の Flush 関数呼び出しで書き込みは完了する error = writer.Flush(); } // ファイル書き込み用ストリームを解放する writer.Release(); } // ファイルを閉じる file.Close(); } if (error != SFERR_NO_ERROR) { // エラーが発生したとき ... }
可変長バッファストリームによるファイル書き込み | |
---|---|
ストリームにはバッファがあります。 SFXFile::GetStreamWriter 関数で size 引数を指定せずにファイル書き込み用ストリームを取得しているので、 可変長バッファが使用されます。 このため、 ストリームバッファは出力ファイルに書き込む全データと同じサイズまで拡張されます。 SFXAnsiStringStreamWriter::WriteSFXAnsiString 関数は、 string 変数のデータをストリームバッファに書き込みます。 SFXStreamWriter::Flush 関数は、 ストリームバッファ内のデータをファイルに書き込みます。 |
例 17.24. 可変長バッファストリームによる TCP ソケット通信
// コールバック関数で使用するので、_socket はクラスのメンバ変数として定義する class MyClass { private: SFXTCPSocket _socket; // SFXTCPSocket インスタンス SFXAnsiStringStreamReader _reader; // データ受信用ストリーム SFXAnsiStringStreamWriter _writer; // データ送信用ストリーム public: Void Start(Void); XALLBACK_DECLARE_SFXTCPSOCKET(OnConnect) XALLBACK_DECLARE_SFXANSISTRINGSTREAMREADER(OnFetch) XALLBACK_DECLARE_SFXANSISTRINGSTREAMWRITER(OnFlush) }; Void MyClass::Start(Void) { SFCError error; SFXSocketAddress host("www.example.com:80"); // ソケットを開く if ((error = _socket.Open()) == SFERR_NO_ERROR) { // サーバーに接続する // ※1. 接続要求の結果は、OnConnect 関数に通知される // ※2. ホスト名(host)は自動的に解決される error = _socket.Connect(host, XALLBACK_INTERNAL(OnConnect)); } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // ソケットを閉じる _socket.Close(); } return; } // 接続要求の結果が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXTCPSOCKET(MyClass, OnConnect, error) { // 送信する文字列 static AChar message[] = "GET / HTTP/1.0\r\n\r\n"; if (error == SFERR_NO_ERROR) { // データ送信用ストリームを取得する // ※ size 引数を指定していないのでストリームバッファは可変長 if ((error = _socket.GetStreamWriter(&_writer)) == SFERR_NO_ERROR) { // message 変数からストリームバッファにデータを書き込む // ※ message 変数のサイズに合わせてバッファは自動的に拡張される if ((error = _writer.Write(message, lengthof(message))) == SFERR_NO_ERROR) { // フラッシュを行う: 実際にストリームバッファからソケットにデータを送信する // ※ データ送信(フラッシュ)の結果は、OnFlush 関数に通知される error = _writer.Flush(XALLBACK_INTERNAL(OnFlush)); } } } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // データ送信用ストリームを解放する _writer.Release(); // ソケットを閉じる _socket.Close(); } return; } // データ送信(フラッシュ)の結果が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXANSISTRINGSTREAMWRITER(MyClass, OnFlush, error) { // 送信が終わったのでデータ送信用ストリームを解放する _writer.Release(); if (error == SFERR_NO_ERROR) { // データ受信用ストリームを取得する // ※ size 引数を指定していないのでストリームバッファは可変長 if ((error = _socket.GetStreamReader(&_reader)) == SFERR_NO_ERROR) { // フェッチを行う: 実際にソケットからストリームバッファにデータを受信する // ※1. データ受信(フェッチ)の結果は、OnFetch 関数に通知される // ※2. 受信するデータのサイズに合わせてバッファは自動的に拡張される error = _reader.Fetch(XALLBACK_INTERNAL(OnFetch)); } } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // データ受信用ストリームを解放する _reader.Release(); // ソケットを閉じる _socket.Close(); } return; } // データ受信(フェッチ)の結果が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXANSISTRINGSTREAMREADER(MyClass, OnFetch, error) { SFXAnsiString string; if (error == SFERR_NO_ERROR) { // ストリームバッファから string 変数にデータを読み込む _reader >> string; // string 変数の内容をデバッグウィンドウに表示する TRACE("%s", string.GetCString()); } // 受信が終わったのでデータ受信用ストリームを解放する _reader.Release(); // ソケットを閉じる _socket.Close(); return; }
可変長バッファストリームによる TCP ソケット通信 | |
---|---|
ストリームにはバッファがあります。 SFXTCPSocket::GetStreamReader / SFXTCPSocket::GetStreamWriter 関数で size 引数を指定せずにデータ送受信用ストリームを取得しているので、 可変長バッファが使用されます。 このため、ストリームバッファに送受信する全データと同じサイズまで拡張されます。 SFXAnsiStringStreamWriter::WriteSFXAnsiString 関数は、 string 変数のデータをストリームバッファに書き込みます。 SFXAnsiStringStreamReader::ReadSFXAnsiString 関数は、 ストリームバッファからデータを読み込み、string 変数に格納します。 SFXStreamWriter::Flush 関数は、 ストリームバッファ内のデータを TCP ソケット通信ネットワークに送信します。 SFXStreamReader::Fetch 関数は、 TCP ソケット通信ネットワークからデータを受信し、ストリームバッファに読み込みます。 |
固定長バッファストリームとは、 読み書きするデータに関係なくバッファのサイズが固定であるストリームのことです。
データがバッファサイズよりも大きい場合はストリームに複数回読み書きを行う必要があります。
固定長バッファストリームは、size 引数を指定してストレージの GetStreamReader / GetStreamWriter 関数を呼び出すことにより取得できます。 バッファサイズは、size 引数に指定した値で設定されます。
例 17.25. 固定長バッファストリームによるファイル入力
SFCError error; // エラー値 SFXFile file; // ファイルクラス のインスタンス SFXAnsiStringStreamReader reader; // ファイル読み込み用ストリーム SFXAnsiString stringFromFile; // 読み込む文字列 SFXAnsiString tempString; // 読み込みモードでファイルを開く if ((error = file.OpenReadOnly(SFXPath("/dir/data.txt"))) == SFERR_NO_ERROR) { // ファイル読み込み用ストリームを取得する // ※ size 引数を指定しているのでストリームバッファは固定長(バッファサイズ: 1024 バイト) if ((error = file.GetStreamReader(1024, &reader)) == SFERR_NO_ERROR) { // ファイルの終端に到達するまで繰り返す while ((error == SFERR_NO_ERROR) && !reader.Ends()) { // ※ バッファサイズよりも大きなデータは複数回 Fetch 関数を呼び出して読み込む // フェッチを行う: ファイルからストリームバッファにデータを読み込む // ※ ストリームバッファは固定長(バッファサイズ: 1024 バイト)なので、1024 バイトまでのデータしか読み込まれない if ((error = reader.Fetch()) == SFERR_NO_ERROR) { // tempString にデータを読み込む if ((error = reader.ReadSFXAnsiString(&tempString)) == SFERR_NO_ERROR) { // stringFromFile の末尾に tempString を加える stringFromFile += tempString; } } } // ファイル読み込み用ストリームを解放する reader.Release(); } // ファイルを閉じる file.Close(); } if (error != SFERR_NO_ERROR) { // エラーが発生したとき ... }
固定長バッファストリームによるファイル読み込み | |
---|---|
SFXFile::GetStreamReader 関数の呼び出しで size 引数にバッファサイズ 1024 バイトを設定しているので、 このサイズの固定長ストリームバッファを使用するストリーム経由でファイル読み込みが行われます。 1 回の SFXStreamReader::Fetch 関数の呼び出しで 1024 バイトまでのデータしか読み込まれません。 1024 バイトよりも大きなデータの読み込みは、 SFXStreamReader::Fetch 関数と SFXAnsiStringStreamReader::ReadSFXAnsiString 関数の呼び出しを複数回繰り返す必要があります。 |
例 17.26. 固定長バッファストリームによるファイル出力
SFCError error; // エラー値 SFXFile file; // ファイル SFXAnsiStringStreamWriter writer; // ファイル書き込み用ストリーム SFXAnsiString string("abcdefghijklmnopqrstuvwxyz"); // 書き込む文字列 ACharConstPtr _p = string.GetBuffer(); // 文字列を指すポインタ ACharConstPtr _endOfString = _p + string.GetLength(); // 文字列の末尾 SInt32 bufferSize = 1024; // 読み書きモードでファイルを開く if ((error = file.OpenReadWrite(SFXPath("/dir/data.txt"))) == SFERR_NO_ERROR) { // ファイル書き込み用ストリームを取得する // ※ size 引数を指定しているのでストリームバッファは固定長(バッファサイズ: 1024 バイト) if ((error = file.GetStreamWriter(bufferSize, &writer)) == SFERR_NO_ERROR) { for (; (error == SFERR_NO_ERROR) && (_p < _endOfString) ; _p += bufferSize) { // バッファサイズよりも大きなデータは複数回 Flush 関数を呼び出して書き込む // 書き込む文字列のサイズ SInt32 size = (_endOfString - _p < bufferSize) ? _endOfString - _p : bufferSize; // _p が指す長さ size の文字列をストリームバッファに書き込む if ((error = writer.Write(_p, size)) == SFERR_NO_ERROR) { // ストリームバッファからファイルにデータを書き込む error = writer.Flush(); } } // ファイル書き込み用ストリームを解放する writer.Release(); } // ファイルを閉じる file.Close(); } if (error != SFERR_NO_ERROR) { // エラーが発生したとき ... }
固定長バッファストリームによるファイル書き込み | |
---|---|
SFXFile::GetStreamWriter 関数の呼び出しで size 引数にバッファサイズ 1024 バイトを設定しているので、 このサイズの固定長ストリームバッファを使用するストリーム経由でファイル書き込みが行われます。 1 回の SFXStreamWriter::Write 関数の呼び出しで 1024 バイトまでのデータしかストリームバッファに書き込めません。 そのため、1 回の SFXStreamWriter::Flush 関数の呼び出しで 1024 バイトまでのデータしかファイルに書き込まれません。 1024 バイトよりも大きなデータの書き込みは、 SFXStreamWriter::Write 関数と SFXStreamWriter::Flush 関数の呼び出しを複数回繰り返す必要があります。 |
例 17.27. 固定長バッファストリームによる TCP ソケット通信
// コールバック関数で使用するので、_socket はクラスのメンバ変数として定義する class MyClass { private: SFXTCPSocket _socket; // TCP ソケットクラス SFXAnsiStringStreamReader _reader; // データ受信用ストリーム SFXAnsiStringStreamWriter _writer; // データ送信用ストリーム SFXAnsiString _sendString; // 送信する文字列 ACharConstPtr _p; ACharConstPtr _end; SInt32 _bufferSize; SFXAnsiString _receiveString; // 受信した文字列 public: Void Start(Void); XALLBACK_DECLARE_SFXTCPSOCKET(OnConnect) XALLBACK_DECLARE_SFXANSISTRINGSTREAMREADER(OnFetch) XALLBACK_DECLARE_SFXANSISTRINGSTREAMWRITER(OnFlush) }; Void MyClass::Start(Void) { SFCError error; SFXSocketAddress host("www.example.com:80"); // 送信する文字列 _sendString = "GET / HTTP/1.0\r\n\r\n"; // バッファサイズ: 1024 _bufferSize = 1024; // ソケットを開く if ((error = _socket.Open()) == SFERR_NO_ERROR) { // サーバーに接続する // ※1. 接続要求の結果は、OnConnect 関数に通知される // ※2. ホスト名(host)は自動的に解決される error = _socket.Connect(host, XALLBACK_INTERNAL(OnConnect)); } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // ソケットを閉じる _socket.Close(); } return; } // 接続要求の結果が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXTCPSOCKET(MyClass, OnConnect, error) { if (error == SFERR_NO_ERROR) { // データ送信用ストリームを取得する // ※ size 引数を指定しているのでストリームバッファは固定長(1024 バイト) if ((error = _socket.GetStreamWriter(_bufferSize, &_writer)) == SFERR_NO_ERROR) { _p = _sendString.GetBuffer(); _end = _p + _sendString.GetLength(); SInt32 size = (_end - _p < _bufferSize) ? _end - _p : _bufferSize; // _p が指す長さ size の文字列をストリームバッファに書き込む if ((error = _writer.Write(_p, size) == SFERR_NO_ERROR) { _p += size; // フラッシュを行う: 実際にストリームバッファからソケットにデータを送信する // ※ データ送信(フラッシュ)の結果は、OnFlush 関数に通知される error = _writer.Flush(XALLBACK_INTERNAL(OnFlush)); } } } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // データ送信用ストリームを解放する _writer.Release(); // ソケットを閉じる _socket.Close(); } return; } // データ送信(フラッシュ)の結果が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXANSISTRINGSTREAMWRITER(MyClass, OnFlush, error) { if (error == SFERR_NO_ERROR) { if (_p < _end) { // 送信するデータがまだ存在するとき: // バッファサイズよりも大きなデータは複数回 Flush 関数を呼び出して送信する SInt32 size = (_end - _p < _bufferSize) ? _end - _p : _bufferSize; // _p が指す長さ size の文字列をストリームバッファに書き込む if ((error = _writer.Write(_p, size) == SFERR_NO_ERROR) { _p += size; // フラッシュを行う: 実際にストリームバッファからソケットにデータを送信する // ※ データ送信(フラッシュ)の結果は、OnFlush 関数に通知される error = _writer.Flush(XALLBACK_INTERNAL(OnFlush)); } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // データ送信用ストリームを解放する _writer.Release(); } } else { // すべてのデータを送信し終えたとき: // データ送信用ストリームを解放する _writer.Release(); // 受信を開始する // データ受信用ストリームを取得する // ※ size 引数を指定しているのでストリームバッファは固定長(1024 バイト) if ((error = _socket.GetStreamReader(_bufferSize, &_reader)) == SFERR_NO_ERROR) { // フェッチを行う: 実際にソケットからストリームバッファにデータを受信する // ※ データ受信(フェッチ)の結果は、OnFetch 関数に通知される error = _reader.Fetch(XALLBACK_INTERNAL(OnFetch)); } } } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // データ受信用ストリームを解放する _reader.Release(); // データ送信用ストリームを解放する _writer.Release(); // ソケットを閉じる _socket.Close(); } return; } // データ受信(フェッチ)の結果が通知されるコールバック関数 XALLBACK_IMPLEMENT_SFXANSISTRINGSTREAMREADER(MyClass, OnFetch, error) { SFXAnsiString string; if (error == SFERR_NO_ERROR) { // ストリームバッファから string 変数にデータを読み込む if ((error = _reader.ReadSFXAnsiString(&string)) != SFERR_NO_ERROR) { _receiveString += string; if (!_reader.Ends()) { // 受信するデータがまだ残っている場合: // バッファサイズよりも大きなデータは複数回 Fetch 関数を呼び出して受信する // フェッチを行う: 実際にソケットからストリームバッファにデータを受信する // ※ データ受信(フェッチ)の結果は、OnFetch 関数に通知される error = _reader.Fetch(XALLBACK_INTERNAL(OnFetch)); } else { // すべてのデータを受信したとき: // 受信したデータをデバッグウィンドウに表示する TRACE("--------"); TRACE("%s", _receiveString.GetCString()); TRACE("--------"); // データ受信用ストリームを解放する _reader.Release(); // ソケットを閉じる _socket.Close(); } } } if (error != SFERR_NO_ERROR) { // エラーが発生したとき // ストリームを解放する _reader.Release(); // ソケットを閉じる _socket.Close(); } return; }
固定長バッファストリーム経由のデータ送受信 | |
---|---|
バッファサイズよりも大きなデータの受信は、 SFXStreamReader::Fetch 関数と、 SFXAnsiStringStreamReader::ReadSFXAnsiString 関数を複数回呼び出して行います。 SFXStreamReader::Fetch 関数を呼び出すたびに OnFetch 関数が起動されます。 一方、バッファサイズよりも大きなデータの送信は、 SFXStreamWriter::Write 関数と SFXStreamWriter::Flush 関数を複数回呼び出して行います。 SFXStreamWriter::Flush 関数を呼び出すたびに OnFlush 関数が起動されます。 |
Copyright(c) 2002 - 2024 Sophia Cradle Incorporated All Rights Reserved. |