Lesen und Schreiben einer Datei aus einer BLOB-Spalte mit chunking in ADO.NET und Visual C# .NET

Eine Microsoft Visual Basic .NET Version dieses Artikels finden Sie unter
317034 .
Eine Microsoft Visual C++ .NET Version dieses Artikels finden Sie unter
317044 .

Zusammenfassung

Dieser Artikel beschreibt, wie Sie Microsoft SQL Server READTEXT und UPDATETEXT-Anweisung zum Lesen und Schreiben von Daten aus Spalten in einer Datenbanktabelle BLOB (LongVarBinary).

Durch Engpässe müssen Sie eine große BLOB-Datei in kleineren Segmenten und Stück Blöcken, anstatt die gesamte BLOB-Datei gleichzeitig abrufen. ADO.NET Data Provider haben jedoch nicht GetChunk und AppendChunk Methoden (Datenzugriffsobjekt) und ActiveX Data Objects (ADO) Recordset -Objekten zur Verfügung. Dieser Artikel beschreibt verschiedene Methoden zum Abrufen von Daten in kleinere Einheiten.

Notizen:
  • Dieser Artikel enthält Beispiele für SqlClient-Datenprovider und dem OLE DB .NET Data Provider. Der einzige Unterschied von Klassennamen sind die Verbindungszeichenfolgen und die SQL-Parameter. Die grundlegende Technik abzurufenden READTEXT und UPDATETEXT-Anweisung entspricht.
  • Der Testeintrag der Categories-Tabelle der Northwind-Beispieldatenbank ist nicht vorhanden. Verwenden Sie im Server-Explorer oder ein anderes Tool Hinzufügen eines Datensatzes mit CategoryName Testfestgelegt. Nachdem Sie in den folgenden Beispielen verwendet, möchten Sie diesen Datensatz aus der Datenbank entfernt. Um den Datensatz zu entfernen, geben Sie folgenden Befehl in SQL Query Analyzer, und drücken Sie F5:
    use Northwinddelete from Categories where CategoryName = 'Test'

zurück zum Anfang

Voraussetzungen

Der folgenden Liste sind die empfohlene Hardware, Software, Netzwerkinfrastruktur, Qualifikationen und Kenntnisse und Servicepacks erforderlich:
  • Microsoft Windows 2000 Professional, Windows 2000 Server, Windows 2000 Advanced Server oder Microsoft Windows NT Server 4.0
  • Microsoft Visual Studio .NET
  • Microsoft SQL Server 7.0 oder höher
Es wird vorausgesetzt, dass Sie mit ADO.NET Grundlagen und Syntax vertraut sind.

zurück zum Anfang

Erstellen Sie ein Projekt und fügen Sie Code hinzu

  1. Öffnen Sie SQL Query Analyzer.
  2. Geben Sie den folgenden Befehl ein, und drücken Sie F5 Northwind die Standarddatenbank ändern:
    use Northwind
  3. Geben Sie folgenden Befehl ein, und drücken Sie F5 zum Einfügen eines neuen Datensatzes in der Categories-Tabelle der Northwind-Datenbank:
    Insert into categories(categoryname) values ('Test')
    Hinweis Sie müssen nur diesen Datensatz der Tabelle Categories hinzufügen, wenn Sie dieses Beispiel verwenden, ohne die vorhandenen Daten in dieser Tabelle ändern möchten.
  4. Erstellen Sie in Visual Studio .NET ein neues Visual C# .NET Windows-Anwendung-Projekt.
  5. Eine Anfang der Datei Form1.cs, fügen Sie die folgenden zwei Codezeilen für System.Data.SQLClient und System.Data.OleDbVerweise zum Projekt hinzufügen:
    using System.Data.SqlClient;using System.Data.OleDb;
  6. Fügen Sie vier Schaltflächen zu Form1 hinzu. Ändern Sie die Text -Eigenschaft der Schaltflächen bzw. SQLBlob2File, OlDbBlob2File, File2OleDbBlobund File2SqlBlob.
  7. Fügen Sie die folgende Zeichenfolge Variablendeklarationen unter der öffentlichen Klasse Form1:
    string destfilepath;string sourcefilepath;

  8. Fügen Sie folgenden Code in das Form Load -Ereignis:
    destfilepath = @"c:\mytest.bmp";sourcefilepath = @"c:\windows\coffee bean.bmp";

  9. Rufen Sie die Prozeduren im Click -Ereignis für jede Schaltfläche:
    // 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. Fügen Sie die folgenden vier Funktionen in Form1:
    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. Drücken Sie F5, um den Code auszuführen
    File2OleDbBlob , um sicherzustellen, dass ein Bild in der SQL Server-Datenbank zu laden, bevor Sie versuchen, eine BMP-Datei auf der Festplatte schreibt.
zurück zum Anfang

Lesen Sie Abschnitte aus einer BLOB-Spalte

Die folgenden Funktionen verwenden SQL Server READTEXT-Anweisung und DataReader Teil der BLOB-Wert in einer Zeile und einer Spalte Rowset abgerufen. Zwei Befehle verwendet: die erste Ruft die Größe des BLOB-Feld und einen Zeiger auf die Position; die zweite führt READTEXT-Befehl. READTEXT-Befehl ruft die Datenmenge in ein Bytearray und erhöht einen Offset. Das Bytearray wird auf die Festplatte über das System.IO.Filesream -Objekt geschrieben. zurück zum Anfang

Abschnitte in einer BLOB-Spalte schreiben

Die folgenden Funktionen verwenden den Befehl und Parameter -Objekten und SQL Server UPDATETEXT-Anweisung Datenblöcke aus einem Bytearray in eine BLOB-Spalte geschrieben. Die BLOB-Spalte darf nicht NULL sein und mit dieser Methode ein einzelnes Byte der Spalte zugewiesen, bevor TEXTPTR abgerufen werden. Der ersten Ausführung die UPDATETEXT-Anweisung wird DeleteParam.Value auf 1 festgelegt. Dies löscht vorhandene Byte aus der Spalte vor dem Einfügen der Abschnitt und verhindert, dass das BLOB überflüssige Daten angehängt. Die UPDATETEXT-Anweisung wird ausgeführt mehrmals, nach jedem Aufruf den Offset mit der Größe des Puffers erhöhen.
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);
}
}

Hinweise
  • Der Code in diesem Artikel beschriebenen kann gegen LongVarChar oder LongVarWChar Spalten ohne Änderung nicht geeignet.
  • Sie müssen die Verbindungszeichenfolge und die SQL-Anweisung entsprechen Ihren eigenen Server ändern. Sie müssen auch hinzufügen Fehler überprüft wird, ob die Abfrage keine Datensätze zurück.
  • READTEXT und UPDATETEXT sind nur für Microsoft SQL Server. Andere Datenbanksysteme möglicherweise ähnliche Befehle, die Sie verwenden können.
zurück zum Anfang

Referenzen

Weitere Informationen zum Lesen und Schreiben von Daten ohne chunking klicken Sie auf die folgenden Artikelnummern klicken, um die Artikel der Microsoft Knowledge Base:

316887 zum Lesen und Schreiben einer Datei aus einer BLOB-Spalte mit ADO.NET und Visual Basic .NET

317017 zum Lesen und Schreiben einer Datei aus einer BLOB-Spalte mit ADO.NET und Visual C++ .NET

317016 zum Lesen und Schreiben einer Datei in eine oder aus einer BLOB-Spalte mit ADO.NET und Visual C# .NET

Weitere Informationen zum Arbeiten mit BLOBs in ADO.NET finden Sie auf der folgenden Website von Microsoft Developer Network (MSDN):
Abrufen von BLOB-Werten aus einer Datenbank
http://msdn.microsoft.com/en-us/library/87z0hy49.aspx
zurück zum Anfang
Eigenschaften

Artikelnummer: 317043 – Letzte Überarbeitung: 21.01.2017 – Revision: 1

Feedback