データベースからの BLOB 値の取得
DataReader の既定の動作は、行全体のデータが使用可能になったときに着信データを行として読み込むことです。バイナリ ラージ オブジェクト (BLOB) には、1 行に収まらない数ギガバイトのデータが含まれる場合があるため、別の処理が必要です。Command.ExecuteReader メソッドはオーバーロード定義されていて、そのうちの 1 つは、CommandBehavior 引数を受け取って DataReader の既定の動作を変更するオーバーロードです。ExecuteReader メソッドに CommandBehavior.SequentialAccess を渡すと、数行のデータを読み込む代わりに、データを受け取った時点で順次読み込むように DataReader の既定の動作を変更できます。これは BLOB やその他のラージ データ構造体を読み込む場合の理想的な処理です。この動作は、データ ソースによって異なる場合があります。たとえば、Microsoft Access から BLOB を返すと、受け取ったデータから順にメモリに読み込むのではなく、BLOB 全体を一度に読み込みます。
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 の総バイト数または総文字数になります。オプションで、データ読み込みの開始位置を示す、配列内のインデックスを指定できます。
Microsoft SQL Server の pubs サンプル データベースから発行者 ID とロゴを返す例を次に示します。発行者 ID (pub_id
) は文字フィールドであり、ロゴはイメージ、つまり BLOB です。logo フィールドはビットマップなので、この例は、GetBytes を使用してバイナリ データを返します。フィールドを順番にアクセスする必要があるため、発行者 ID は現在の行のデータとしてロゴの前にアクセスされることに注意してください。
Dim pubsConn As SqlConnection = New SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=pubs;")
Dim logoCMD As SqlCommand = New SqlCommand("SELECT pub_id, logo FROM pub_info", pubsConn)
Dim fs As FileStream ' Writes the BLOB to a file (*.bmp).
Dim bw As BinaryWriter ' Streams the binary data to the FileStream object.
Dim bufferSize As Integer = 100 ' The size of the BLOB buffer.
Dim outbyte(bufferSize - 1) As Byte ' The BLOB byte() buffer to be filled by GetBytes.
Dim retval As Long ' The bytes returned from GetBytes.
Dim startIndex As Long = 0 ' The starting position in the BLOB output.
Dim pub_id As String = "" ' The publisher id to use in the file name.
' Open the connection and read data into the DataReader.
pubsConn.Open()
Dim myReader As SqlDataReader = logoCMD.ExecuteReader(CommandBehavior.SequentialAccess)
Do While myReader.Read()
' Get the publisher id, which must occur before getting the logo.
pub_id = myReader.GetString(0)
' Create a file to hold the output.
fs = New FileStream("logo" & pub_id & ".bmp", FileMode.OpenOrCreate, FileAccess.Write)
bw = New BinaryWriter(fs)
' Reset the starting byte for a new BLOB.
startIndex = 0
' Read bytes into outbyte() and retain the number of bytes returned.
retval = myReader.GetBytes(1, startIndex, outbyte, 0, bufferSize)
' Continue reading and writing while there are bytes beyond the size of the buffer.
Do While retval = bufferSize
bw.Write(outbyte)
bw.Flush()
' Reposition the start index to the end of the last buffer and fill the buffer.
startIndex += bufferSize
retval = myReader.GetBytes(1, startIndex, outbyte, 0, bufferSize)
Loop
' Write the remaining buffer.
bw.Write(outbyte, 0 , retval - 1)
bw.Flush()
' Close the output file.
bw.Close()
fs.Close()
Loop
' Close the reader and the connection.
myReader.Close()
pubsConn.Close()
[C#]
SqlConnection pubsConn = new SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=pubs;");
SqlCommand logoCMD = new SqlCommand("SELECT pub_id, logo FROM pub_info", pubsConn);
FileStream fs; // Writes the BLOB to a file (*.bmp).
BinaryWriter bw; // Streams the BLOB to the FileStream object.
int bufferSize = 100; // Size of the BLOB buffer.
byte[] outbyte = new byte[bufferSize]; // The BLOB byte[] buffer to be filled by GetBytes.
long retval; // The bytes returned from GetBytes.
long startIndex = 0; // The starting position in the BLOB output.
string pub_id = ""; // The publisher id to use in the file name.
// Open the connection and read data into the DataReader.
pubsConn.Open();
SqlDataReader myReader = logoCMD.ExecuteReader(CommandBehavior.SequentialAccess);
while (myReader.Read())
{
// Get the publisher id, which must occur before getting the logo.
pub_id = myReader.GetString(0);
// Create a file to hold the output.
fs = new FileStream("logo" + pub_id + ".bmp", FileMode.OpenOrCreate, FileAccess.Write);
bw = new BinaryWriter(fs);
// Reset the starting byte for the new BLOB.
startIndex = 0;
// Read the bytes into outbyte[] and retain the number of bytes returned.
retval = myReader.GetBytes(1, startIndex, outbyte, 0, bufferSize);
// Continue reading and writing while there are bytes beyond the size of the buffer.
while (retval == bufferSize)
{
bw.Write(outbyte);
bw.Flush();
// Reposition the start index to the end of the last buffer and fill the buffer.
startIndex += bufferSize;
retval = myReader.GetBytes(1, startIndex, outbyte, 0, bufferSize);
}
// Write the remaining buffer.
bw.Write(outbyte, 0, (int)retval - 1);
bw.Flush();
// Close the output file.
bw.Close();
fs.Close();
}
// Close the reader and the connection.
myReader.Close();
pubsConn.Close();
参照
.NET Framework データ プロバイダによるデータのアクセス | データベースへの BLOB 値の書き込み | OleDbDataReader クラス| OleDbCommand クラス| OdbcDataReader クラス | OdbcCommand クラス | SqlDataReader クラス | SqlCommand クラス | CommandBehavior 列挙体