ストリームを使ってデータの読み書きを行う
ストリームの使用 への移動
RTL の利用:インデックス への移動
どのストリームクラスにも,データを読み書きするための共通のメソッドがいくつかあります。これらのメソッドは,以下の観点で分類されています。
- 読み出された,または書き込まれたバイト数を返すかどうか
- バイト数を知る必要があるかどうか
- エラー時に例外を生成するかどうか
目次 |
読み書きをするためのストリームメソッド
Read メソッドは,指定されたバイト数だけ現在位置からバッファへと読み出します。その後,実際に読み出したバイト数だけ読み書き位置を進めます。Read のプロトタイプは,以下のとおりです。
function Read(var Buffer; Count: Longint): Longint;
Read は,ファイルのバイト数が不明な場合などに使用すると便利です。Read は実際に転送されたバイト数を返すからです。現在位置を超えるデータが Count バイト数に満たない場合は,実際に転送されるバイト数は Count より小さくなります。
Write メソッドは,バッファからストリームへと現在位置から Count バイト分書き込みます。Write のプロトタイプは,以下のとおりです。
function Write(const Buffer; Count: Longint): Longint;
書き込み後,Write により,実際に書き込めたバイト数だけ読み書き位置を進め,関数の戻り値とします。バッファの終端に到達した場合,あるいはストリームがこれ以上のバイト数を受け付けられない場合は,書き込んだバイト数は Count より小さいことがあります。
上記関数と類似した手続きとして ReadBuffer と WriteBuffer があります。これらは,Read や Write とは異なり,読み出されたバイト数や書き込まれたバイト数を返しません。構造体から読み出しをする場合のように,必要なバイト数があらかじめわかっている場合に,これらの手続きは有効です。バイト数を正確に一致させることができない場合,ReadBuffer と WriteBuffer は,例外(EReadError と EWriteError)を生成します。この点が Read,Write メソッドと明確に違います。Read と Write は,要求値とのバイト数の差を返すことができます。ReadBuffer と WriteBuffer のプロトタイプは,次のようになります。
procedure ReadBuffer(var Buffer; Count: Longint); procedure WriteBuffer(const Buffer; Count: Longint);
これらのメソッドは,実際の読み出しや書き込みは Read メソッドと Write メソッドを呼び出すことで実行します。
コンポーネントの読み出しと書き込み
TStream には,コンポーネントの読み書きを行う専用メソッド(ReadComponent と WriteComponent)が定義されています。アプリケーションでこれらのメソッドを使用すると,アプリケーションを作成したり実行時に変更したとき,コンポーネントとそのプロパティを保存できます。
IDE は,この ReadComponent メソッドと WriteComponent メソッドを使ってフォームファイルとの間でコンポーネントの読み書きをします。フォームファイルとの間でコンポーネントを読み書きするとき,ストリームクラスは TFiler クラス,TReader,および TWriter と一緒に動作して,オブジェクトをフォームファイルから読み出したりディスクへ出力します。コンポーネントストリームシステムの使い方については,System.Classes.TStream,System.Classes.TFiler,System.Classes.TReader,System.Classes.TWriter,および System.Classes.TComponent の各クラスを参照してください。
文字列の読み出しと書き込み
読み出しや書き込みの関数に文字列を渡す場合は,正しい構文を知る必要があります。読み出しルーチンと書き込みのルーチンの Buffer パラメータは,それぞれ var 型と const 型です。これらは型のないパラメータなので,ルーチンはこれらの型として渡された変数のアドレスをとります。
文字列の処理の際に最も一般に使用される型は,長い文字列です。ただし,長い文字列を Buffer パラメータとして渡すと,正しい結果を生成できません。長い文字列には,文字列中にサイズ,参照カウント,および文字へのポインタが入っています。そのため,長い文字列の逆参照はポインタ要素に対する結果にはなりません。正しい結果を得るには,文字列を Pointer または PChar にキャストしてから逆参照する必要があります。次に例を示します。
procedure caststring;
var
fs: TFileStream;
const
s: string = 'Hello';
begin
fs := TFileStream.Create('temp.txt', fmCreate or fmOpenWrite);
fs.Write(s, Length(s));// 無意味なデータが生じる
fs.Write(PChar(s)^, Length(s));// これが正しい方法
end;