バイナリ データの取得
適用対象: .NET Framework .NET .NET Standard
既定では、データの行全体が使用可能になるとすぐに、DataReader によって受信データが行として読み込まれます。 バイナリ ラージ オブジェクト (BLOB) には、1 行に収まらない数ギガバイトのデータが含まれる場合があるため、別の処理が必要です。 Command.ExecuteReader メソッドには、CommandBehavior 引数を受け取って DataReader の既定の動作を変更するオーバーロードがあります。 ExecuteReader メソッドに SequentialAccess を渡すと、データの行を読み込む代わりに、データを受け取った時点で順次読み込むように、DataReader の既定の動作を変更できます。 これは BLOB やその他の大きなデータ構造を読み込む場合に理想的な処理です。
Note
SequentialAccess を使用するように DataReader を設定するときは、返されたフィールドにアクセスする順序に注意してください。 使用可能になるとすぐに行全体を読み込む DataReader の既定の動作では、次の行が読み取られるまでは、返されたフィールドに任意の順序でアクセスできます。 しかし、SequentialAccess を使用しているときは、DataReader によって返された各フィールドに順番にアクセスする必要があります。 たとえば、クエリが 3 つの列 (3 番目の列は BLOB) を返す場合、最初のフィールドおよび 2 番目のフィールドの値は、3 番目のフィールドの BLOB データにアクセスする前に返す必要があります。 最初のフィールドまたは 2 番目のフィールドの前に 3 番目のフィールドにアクセスした場合は、最初のフィールドと 2 番目のフィールドの値は使用できなくなります。 これは、SequentialAccess によって、DataReader はデータを順番に返すように変更されており、DataReader による読み取りが通過した後のデータは使用できなくなるためです。
BLOB フィールドのデータにアクセスするときは、DataReader の GetBytes 型または GetChars 型のアクセサーを使用します。これらのアクセサーでは、データは配列に設定されます。 文字データ用の GetString を使用することもできますが、システム リソースを節約するためには、BLOB 値全体を 1 つの文字列変数に読み込むことは望ましくありません。 特定のバッファー サイズのデータを返すように指定する代わりに、返されたデータから読み込む先頭バイトまたは先頭文字の開始位置を指定できます。 GetBytes と GetChars では、返されたバイト数または文字数を表す long
値が返されます。 GetBytes または GetChars に null 配列を渡した場合、返される long 値は BLOB の総バイト数または総文字数になります。 オプションで、データ読み込みの開始位置を示す、配列内のインデックスを指定できます。
例
次の例は、pubs サンプル データベースから発行者 ID とロゴを取得します。 発行者 ID (pub_id
) は文字フィールドであり、ロゴはイメージ、つまり、BLOB です。 logo フィールドはビットマップなので、この例では、GetBytes を使用してバイナリ データを返します。 フィールドには順番にアクセスする必要があるため、現在の行のデータに対して発行者 ID はロゴの前にアクセスされることに注意してください。
// Assumes that connection is a valid SqlConnection object.
SqlCommand command = new SqlCommand(
"SELECT pub_id, logo FROM pub_info", connection);
// Writes the BLOB to a file (*.bmp).
System.IO.FileStream stream;
// Streams the BLOB to the FileStream object.
System.IO.BinaryWriter writer;
// Size of the BLOB buffer.
int bufferSize = 100;
// The BLOB byte[] buffer to be filled by GetBytes.
byte[] outByte = new byte[bufferSize];
// The bytes returned from GetBytes.
long retval;
// The starting position in the BLOB output.
long startIndex = 0;
// The publisher id to use in the file name.
string pubID = "";
// Open the connection and read data into the DataReader.
connection.Open();
SqlDataReader reader = command.ExecuteReader(CommandBehavior.SequentialAccess);
while (reader.Read())
{
// Get the publisher id, which must occur before getting the logo.
pubID = reader.GetString(0);
// Create a file to hold the output.
stream = new System.IO.FileStream(
"logo" + pubID + ".bmp", System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write);
writer = new System.IO.BinaryWriter(stream);
// Reset the starting byte for the new BLOB.
startIndex = 0;
// Read bytes into outByte[] and retain the number of bytes returned.
retval = reader.GetBytes(1, startIndex, outByte, 0, bufferSize);
// Continue while there are bytes beyond the size of the buffer.
while (retval == bufferSize)
{
writer.Write(outByte);
writer.Flush();
// Reposition start index to end of last buffer and fill buffer.
startIndex += bufferSize;
retval = reader.GetBytes(1, startIndex, outByte, 0, bufferSize);
}
// Write the remaining buffer.
writer.Write(outByte, 0, (int)retval);
writer.Flush();
// Close the output file.
writer.Close();
stream.Close();
}
// Close the reader and the connection.
reader.Close();
connection.Close();