読み取り、ADO.NET および Visual C# .NET のチャンクを使用して BLOB カラムとの間にファイルを書き込む方法

Microsoft Visual Basic .NET 版のこの資料には、次を参照してください。
317034
Microsoft Visual C++ .NET 版のこの資料には、次を参照してください。
317044

概要

この資料では、データベース テーブル内の列を BLOB (LongVarBinary) からデータを読み書きするための Microsoft SQL Server READTEXT、UPDATETEXT ステートメントを使用する方法について説明します。

ネットワークの制約上より小さいチャンクでサイズの大きな BLOB ファイルを取得し、BLOB ファイル全体を一度に取得するのではなく、一緒のチャンクの像を把握する必要があります。ただし、ADO.NET データ プロバイダーには、 GetChunkメソッドとAppendChunkメソッド データ アクセス オブジェクト (DAO) または ActiveX データ オブジェクト (ADO)レコード セットオブジェクトに使用できるはありません。この資料より小さいチャンクでデータを取得するさまざまな方法について説明します。

メモ:
  • この資料には、SqlClient データ プロバイダーと OLE DB .NET データ プロバイダーの両方の例が含まれています。クラス名以外の唯一の違いは、接続文字列と SQL パラメーターの宣言です。READTEXT、UPDATETEXT ステートメントを取得する基本的な手法は、同じです。
  • ノースウィンド サンプル データベースの [商品区分] テーブル内のテスト レコードは存在しません。サーバー エクスプ ローラーを使用する必要がありますか、 [区分名]のレコードを追加するのには別のツールのセットをテストします。後、次のサンプルを使用すると、データベースからこのレコードを削除する場合があります。レコードを削除するには、SQL クエリ アナライザーで、次のコマンドを入力し、F5 キーを押します。
    use Northwinddelete from Categories where CategoryName = 'Test'

先頭に戻る

要件

次の項目は、推奨されるハードウェア、ソフトウェア、ネットワーク インフラストラクチャ、スキルと知識、および必要な service pack について説明します。
  • サーバー、または Microsoft Windows NT 4.0 サーバーを Microsoft Windows 2000 Professional、Windows 2000 Server、Windows 2000 高度な
  • Microsoft Visual Studio .NET
  • 7.0 またはそれ以降の Microsoft SQL Server
この資料では、ADO.NET の基本事項と構文に精通している場合を想定しています。

先頭に戻る

プロジェクトを作成し、コードを追加します。

  1. SQL クエリ アナライザーを開きます。
  2. 次のコマンドを入力し、northwind データベースを既定のデータベースを変更するのには f5 キーを押します。
    use Northwind
  3. 次のコマンドを入力し、ノースウィンド データベースの [商品区分] テーブルに新しいレコードを挿入するのには f5 キーを押します。
    Insert into categories(categoryname) values ('Test')
    注: このテーブルの既存データのいずれかを変更することがなく次の使用例を使用する場合、[商品区分] テーブルにこのレコードを追加する必要がのみ。
  4. Visual Studio .net では、新しい Visual C# .NET の Windows アプリケーション プロジェクトを作成します。
  5. Athe の上部、Form1.cs ファイルは、 System.Data.SQLClientSystem.Data.OleDbのプロジェクトへの参照を追加するコードの次の 2 行を追加します。
    using System.Data.SqlClient;using System.Data.OleDb;
  6. 4 つのボタンを Form1 に追加します。それぞれにSQLBlob2FileOlDbBlob2FileFile2OleDbBlobFile2SqlBlobボタンのTextプロパティを変更します。
  7. Form1 パブリック クラスに次の文字列変数宣言を追加します。
    string destfilepath;string sourcefilepath;

  8. フォームのLoadイベントでは、次のコードを貼り付けます。
    destfilepath = @"c:\mytest.bmp";sourcefilepath = @"c:\windows\coffee bean.bmp";

  9. 各ボタンのClickイベント プロシージャを呼び出します。
    // Click event for the button labeled SqlBlob2File.SqlChunkBlob2File(destfilepath);

    // Click event for the button labeled OLDbBlob2File.
    OlDbChunkBlob2File(destfilepath);

    // Click event for the button labeled File2OleDbBlob.
    ChunkFile2OleDbBlob(sourcefilepath);

    //Click event for the button labeled File2SqlBlob.
    ChunkFile2SqlBlob(sourcefilepath);

  10. Form1 に次の 4 つの関数を貼り付けます。
    public void SqlChunkBlob2File(string DestFilePath){
    try
    {
    int PictureCol = 0; // position of Picture column in DataReader
    int BUFFER_LENGTH = 32768; // chunk size
    SqlConnection cn = new SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=Northwind;");

    // Make sure Photo is non-NULL and return TEXTPTR to it.

    SqlCommand cmdGetPointer = new SqlCommand("SELECT @Pointer=TEXTPTR(Picture), @Length=DataLength(Picture) FROM Categories WHERE CategoryName='Test'", cn);
    SqlParameter PointerOutParam = cmdGetPointer.Parameters.Add("@Pointer", SqlDbType.VarBinary, 100);
    PointerOutParam.Direction = ParameterDirection.Output;
    SqlParameter LengthOutParam = cmdGetPointer.Parameters.Add("@Length", SqlDbType.Int);
    LengthOutParam.Direction = ParameterDirection.Output;
    cn.Open();
    cmdGetPointer.ExecuteNonQuery();
    if(PointerOutParam.Value == null)
    {
    cn.Close();
    // Add code to handle NULL BLOB.
    return;
    }

    // Set up READTEXT command, parameters, and open BinaryReader.

    SqlCommand cmdReadBinary = new SqlCommand("READTEXT Categories.Picture @Pointer @Offset @Size HOLDLOCK", cn);
    SqlParameter PointerParam = cmdReadBinary.Parameters.Add("@Pointer", SqlDbType.Binary, 16);
    SqlParameter OffsetParam = cmdReadBinary.Parameters.Add("@Offset", SqlDbType.Int);
    SqlParameter SizeParam = cmdReadBinary.Parameters.Add("@Size", SqlDbType.Int);
    SqlDataReader dr;
    System.IO.FileStream fs = new System.IO.FileStream(DestFilePath, System.IO.FileMode.Create, System.IO.FileAccess.Write);
    int Offset= 0;
    OffsetParam.Value = Offset;
    Byte []Buffer = new Byte[BUFFER_LENGTH ];


    // Read buffer full of data and write to the file stream.

    do
    {
    PointerParam.Value = PointerOutParam.Value;

    // Calculate buffer size - may be less than BUFFER_LENGTH for last block.

    if( (Offset + BUFFER_LENGTH) >= System.Convert.ToInt32(LengthOutParam.Value))
    SizeParam.Value = System.Convert.ToInt32(LengthOutParam.Value) - Offset;
    else SizeParam.Value = BUFFER_LENGTH;

    dr = cmdReadBinary.ExecuteReader(CommandBehavior.SingleResult);
    dr.Read();
    dr.GetBytes(PictureCol, 0, Buffer, 0, System.Convert.ToInt32(SizeParam.Value));
    dr.Close();
    fs.Write(Buffer, 0, System.Convert.ToInt32(SizeParam.Value));
    Offset += System.Convert.ToInt32(SizeParam.Value);
    OffsetParam.Value = Offset;
    }while(Offset < System.Convert.ToInt32(LengthOutParam.Value));

    fs.Close();
    cn.Close();
    }
    catch(SqlException ex)
    {
    MessageBox.Show (ex.Message);
    }
    }

    public void OleDbChunkBlob2File(string DestFilePath)
    {
    try
    {
    int PictureCol= 0; // Position of picture column in DataReader.
    int BUFFER_LENGTH = 32768;// Chunk size.
    OleDbConnection cn = new OleDbConnection("Provider=SQLOLEDB;Data Source=localhost;Integrated Security=SSPI;Initial Catalog=Northwind;");

    // Make sure Photo is non-NULL and return TEXTPTR to it.

    OleDbCommand cmdGetPointer = new OleDbCommand("SELECT ?=TEXTPTR(Picture), ?=DataLength(Picture) FROM Categories WHERE CategoryName='Test'", cn);
    OleDbParameter PointerOutParam = cmdGetPointer.Parameters.Add("@Pointer", OleDbType.VarBinary, 100);
    PointerOutParam.Direction = ParameterDirection.Output;
    OleDbParameter LengthOutParam = cmdGetPointer.Parameters.Add("@Length", OleDbType.Integer);
    LengthOutParam.Direction = ParameterDirection.Output;
    cn.Open();
    cmdGetPointer.ExecuteNonQuery();
    if(PointerOutParam.Value == DBNull.Value )
    {
    cn.Close();
    // Add code to deal with NULL BLOB.
    return;
    }

    // Set up READTEXT command, parameters, and open BinaryReader.

    OleDbCommand cmdReadBinary = new OleDbCommand("READTEXT Categories.Picture ? ? ? HOLDLOCK", cn);
    OleDbParameter PointerParam = cmdReadBinary.Parameters.Add("@Pointer", OleDbType.Binary, 16);
    OleDbParameter OffsetParam = cmdReadBinary.Parameters.Add("@Offset", OleDbType.Integer);
    OleDbParameter SizeParam = cmdReadBinary.Parameters.Add("@Size", OleDbType.Integer);
    OleDbDataReader dr;
    System.IO.FileStream fs = new System.IO.FileStream(DestFilePath, System.IO.FileMode.Create, System.IO.FileAccess.Write);
    int Offset= 0;
    OffsetParam.Value = Offset;
    Byte[] Buffer = new Byte[BUFFER_LENGTH];

    //Read buffer full of data and write to the file stream.

    do
    {
    PointerParam.Value = PointerOutParam.Value;

    // Calculate buffer size - may be less than BUFFER_LENGTH for last block.

    if((Offset + BUFFER_LENGTH) >= System.Convert.ToInt32(LengthOutParam.Value))
    SizeParam.Value = System.Convert.ToInt32(LengthOutParam.Value) - Offset;
    else SizeParam.Value = BUFFER_LENGTH;

    dr = cmdReadBinary.ExecuteReader(CommandBehavior.SingleResult);
    dr.Read();
    dr.GetBytes(PictureCol, 0, Buffer, 0, System.Convert.ToInt32(SizeParam.Value));
    dr.Close();
    fs.Write(Buffer, 0, System.Convert.ToInt32(SizeParam.Value));
    Offset += System.Convert.ToInt32(SizeParam.Value);
    OffsetParam.Value = Offset;
    }while( Offset < System.Convert.ToInt32(LengthOutParam.Value));

    fs.Close();
    cn.Close();
    }
    catch(OleDbException ex)
    {
    MessageBox.Show (ex.Message);
    }
    }

  11. 、コードを実行し、をクリックし、f5 キーを押してください。
    File2OleDbBlobのディスク上の .bmp ファイルに書き込むしようとする前に、SQL Server データベース内のイメージをロードするかどうかを確認します。
先頭に戻る

BLOB 列からの読み取りの単位

次の関数は、単一行、単一列の行セット内の BLOB 値の一部を取得するために SQL Server READTEXT ステートメント、DataReader を使用します。2 つのコマンドを使用: 最初の BLOB のフィールドとその場所へのポインターのサイズを取得します。2 つ目は、READTEXT コマンドを実行します。READTEXT コマンドでは、バイト配列内のデータのチャンクを取得し、オフセットをインクリメントします。バイト配列は、 System.IO.Filesreamオブジェクトをディスクに書き込まれます。先頭に戻る

チャンクを BLOB 列に書き込みます

次の関数では、BLOB 列をバイト配列からのデータのチャンクを作成するのには、コマンドパラメーターオブジェクトと SQL Server の UPDATETEXT ステートメントを使用します。BLOB 列は、TEXTPTR を取得する前に、列に 1 バイトが割り当てられているために、この方法では、NULL をすることはできません。UPDATETEXT ステートメントの最初の実行、 DeleteParam.Valueが 1 に設定されています。これは、チャンクを挿入する前に既存のバイトを列から削除され、BLOB から余分なデータが追加されます。UPDATETEXT ステートメントは、実行の複数回、各呼び出しの後、バッファーのサイズとオフセットをインクリメントします。
private void ChunkFile2SqlBlob(string SourceFilePath){
try
{
int BUFFER_LENGTH = 32768; // Chunk size.
SqlConnection cn = new SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=Northwind;");

// Make sure Photo is non-NULL and return TEXTPTR to it.

SqlCommand cmdGetPointer = new SqlCommand("SET NOCOUNT ON;UPDATE Categories SET Picture = 0x0 WHERE CategoryName='Test';" +
"SELECT @Pointer=TEXTPTR(Picture) FROM Categories WHERE CategoryName='Test'", cn);
SqlParameter PointerOutParam = cmdGetPointer.Parameters.Add("@Pointer", SqlDbType.VarBinary, 100);
PointerOutParam.Direction = ParameterDirection.Output;
cn.Open();
cmdGetPointer.ExecuteNonQuery();

// Set up UPDATETEXT command, parameters, and open BinaryReader.

SqlCommand cmdUploadBinary = new SqlCommand("UPDATETEXT Categories.Picture @Pointer @Offset @Delete WITH LOG @Bytes", cn);
SqlParameter PointerParam = cmdUploadBinary.Parameters.Add("@Pointer", SqlDbType.Binary, 16);
SqlParameter OffsetParam= cmdUploadBinary.Parameters.Add("@Offset", SqlDbType.Int);
SqlParameter DeleteParam = cmdUploadBinary.Parameters.Add("@Delete", SqlDbType.Int);
DeleteParam.Value = 1; // delete 0x0 character
SqlParameter BytesParam = cmdUploadBinary.Parameters.Add("@Bytes", SqlDbType.Binary, BUFFER_LENGTH);
System.IO.FileStream fs = new System.IO.FileStream(SourceFilePath, System.IO.FileMode.Open, System.IO.FileAccess.Read);
System.IO.BinaryReader br = new System.IO.BinaryReader(fs);
int Offset = 0;
OffsetParam.Value = Offset;


// Read buffer full of data and execute UPDATETEXT statement.

Byte [] Buffer = br.ReadBytes(BUFFER_LENGTH);
while(Buffer.Length > 0)
{
PointerParam.Value = PointerOutParam.Value;
BytesParam.Value = Buffer;
cmdUploadBinary.ExecuteNonQuery();
DeleteParam.Value = 0; //Do not delete any other data.
Offset += Buffer.Length;
OffsetParam.Value = Offset;
Buffer = br.ReadBytes(BUFFER_LENGTH);
}

br.Close();
fs.Close();
cn.Close();
}
catch(SqlException ex)
{
MessageBox.Show (ex.Message);
}
}

public void ChunkFile2OleDbBlob(string SourceFilePath)
{
try
{
int BUFFER_LENGTH = 32768; // chunk size
OleDbConnection cn = new OleDbConnection("Provider=SQLOLEDB;Data Source=localhost;Integrated Security=SSPI;Initial Catalog=Northwind;");

// Make sure Photo is non-NULL and return TEXTPTR to it.

OleDbCommand cmdGetPointer = new OleDbCommand("SET NOCOUNT ON;UPDATE Categories SET Picture = 0x0 WHERE CategoryName='Test';" +
"SELECT ?=TEXTPTR(Picture) FROM Categories WHERE CategoryName='Test'", cn);
OleDbParameter PointerOutParam = cmdGetPointer.Parameters.Add("@Pointer", OleDbType.VarBinary, 100);
PointerOutParam.Direction = ParameterDirection.Output;
cn.Open();
cmdGetPointer.ExecuteNonQuery();

// Set up UPDATETEXT command, parameters, and open BinaryReader.

OleDbCommand cmdUploadBinary = new OleDbCommand("UPDATETEXT Categories.Picture ? ? ? WITH LOG ?", cn);
OleDbParameter PointerParam = cmdUploadBinary.Parameters.Add("@Pointer", OleDbType.Binary, 16);
OleDbParameter OffsetParam = cmdUploadBinary.Parameters.Add("@Offset", OleDbType.Integer);
OleDbParameter DeleteParam = cmdUploadBinary.Parameters.Add("@Delete", OleDbType.Integer);
DeleteParam.Value = 1; // delete 0x0 character
OleDbParameter BytesParam = cmdUploadBinary.Parameters.Add("@Bytes", OleDbType.Binary, BUFFER_LENGTH);
System.IO.FileStream fs = new System.IO.FileStream(SourceFilePath, System.IO.FileMode.Open, System.IO.FileAccess.Read);
System.IO.BinaryReader br = new System.IO.BinaryReader(fs);
int Offset= 0;
OffsetParam.Value = Offset;


// Read buffer full of data and execute UPDATETEXT statement.

Byte[] Buffer = br.ReadBytes(BUFFER_LENGTH);
while(Buffer.Length > 0)
{
PointerParam.Value = PointerOutParam.Value;
BytesParam.Value = Buffer;
cmdUploadBinary.ExecuteNonQuery();
DeleteParam.Value = 0;// Do not delete any other data.
Offset += Buffer.Length;
OffsetParam.Value = Offset;
Buffer = br.ReadBytes(BUFFER_LENGTH);
}

br.Close();
fs.Close();
cn.Close();
}
catch(OleDbException ex)
{
MessageBox.Show (ex.Message);
}
}

注:
  • この資料に記載されているコードを変更することがなくするか、LongVarWChar の列に対して使用するため適さない場合があります。
  • 独自のサーバーに対応する SQL ステートメントと接続文字列を変更する必要があります。エラー、クエリにレコードが返されない場合にチェックを追加する必要があります。
  • READTEXT、UPDATETEXT は、Microsoft SQL Server に固有です。別のデータベース システムに使用できるようなコマンドがあります。
先頭に戻る

関連情報

チャンクに分割することがなくデータを読み書きする方法の詳細については、マイクロソフト サポート技術情報の記事を表示するのには次の資料番号をクリックします。

316887方法は、読み取りし、書き込みのファイルに BLOB 列から ADO.NET および Visual Basic .NET を使用して

317017方法は、読み取りし、書き込みのファイルに BLOB 列から ADO.NET および Visual C++ .NET を使用して

317016方法を読み取るし、ADO.NET および Visual C# .NET を使用して BLOB カラムとの間にファイルを書き込む

ADO.NET で Blob の処理に関する詳細については、次の Microsoft Developer Network (MSDN) Web サイトを参照してください。
データベースから BLOB 値を取得します。
http://msdn.microsoft.com/en-us/library/87z0hy49.aspx
先頭に戻る
プロパティ

文書番号:317043 - 最終更新日: 2017/02/01 - リビジョン: 1

フィードバック