Obtention de valeurs BLOB à partir d'une base de données

Le comportement par défaut du DataReader est de charger les données entrantes comme une ligne dès qu'une ligne de données complète est disponible. Les objets binaires volumineux ou BLOB doivent néanmoins être traités différemment, car ils peuvent renfermer plusieurs gigaoctets de données qu'une seule ligne ne suffirait pas à contenir. La méthode Command.ExecuteReader a une surcharge qui prendra un argument CommandBehavior pour modifier le comportement par défaut du DataReader. Vous pouvez passer CommandBehavior.SequentialAccess à la méthode ExecuteReader pour modifier le comportement par défaut du DataReader de sorte qu'au lieu de charger des lignes de données, il chargera les données de façon séquentielle, telle qu'elles sont reçues. Ceci est idéal pour charger les BLOB ou d'autres grosses structures de données. Notez que ce comportement peut différer selon votre source de données. Par exemple, un BLOB retourné de Microsoft Access est entièrement chargé dans la mémoire, au lieu que les données soient chargées de façon séquentielle à mesure qu'elles arrivent.

Lors de la configuration du DataReader pour qu'il utilise SequentialAccess, il est important de noter l'ordre dans lequel vous accédez aux champs retournés. Le comportement par défaut du DataReader, qui charge une ligne entière dès qu'elle est disponible, vous permet d'accéder aux champs retournés dans n'importe quel ordre jusqu'à la lecture de la ligne suivante. Lors de l'utilisation de SequentialAccess, cependant, vous devez accéder dans l'ordre aux différents champs retournés par le DataReader. Par exemple, si votre requête retourne trois colonnes, la troisième étant un BLOB, vous devez retourner les valeurs des premier et deuxième champs avant d'accéder aux données BLOB du troisième champ. Si vous accédez au troisième champ avant le premier ou le deuxième, les valeurs de ces champs ne seront plus disponibles. Ceci s'explique par le fait que SequentialAccess a modifié le DataReader pour retourner les données dans l'ordre et les données ne seront plus disponibles après que DataReader en a dépassé la fin.

Lorsque vous accédez aux données du champ BLOB, utilisez l'accesseur typé GetBytes ou GetChars du DataReader qui remplit un tableau avec les données. Vous pouvez également utiliser GetString pour les données de type caractère ; toutefois, pour économiser les ressources système vous souhaiterez peut-être ne pas charger la valeur entière du BLOB dans une seule variable de chaîne. Vous pouvez spécifier une taille de mémoire tampon spécifique des données à retourner ainsi qu'un emplacement de départ pour le premier octet ou le premier caractère lu des données retournées. GetBytes et GetChars retourneront une valeur long, qui représente le nombre d'octets ou de caractères retournés. Si vous passez un tableau null GetBytes ou GetChars, la valeur de type long retournée sera le nombre total d'octets ou de caractères contenus dans le BLOB. Vous pouvez éventuellement spécifier un index dans le tableau comme position de départ pour les données en cours de lecture.

L'exemple suivant retourne l'ID et le logo de l'éditeur de l'exemple de la base de données pubs dans Microsoft SQL Server. L'ID de l'éditeur (pub_id) est un champ texte et le logo est une image (un BLOB). Étant donné que le champ logo est une bitmap, l'exemple retourne des données binaires au moyen de GetBytes. Notez que pour la ligne de données actuelle, il faut accéder à l'ID de l'éditeur avant d'accéder au logo, car l'accès aux champs doit être séquentiel.

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();

Voir aussi

Utilisation des fournisseurs de données .NET Framework pour l'accès aux données | Écriture de valeurs BLOB dans une base de données | OleDbDataReader, classe | OleDbCommand, classe | OdbcDataReader, classe | OdbcCommand, classe | SqlDataReader, classe | SqlCommand, classe | CommandBehavior, énumération