Compartir a través de


Obtener valores BLOB a partir de una base de datos

El objeto DataReader carga de forma predeterminada los datos que recibe en una fila, siempre que hay disponibles suficientes datos para llenarla. Sin embargo, los BLOB (Binary Large Object, objeto binario grande) se deben tratar de otra forma ya que pueden llegar a contener grandes cantidades de datos (del orden de gigabytes) que no pueden almacenarse en una sola fila. El método Command.ExecuteReader se puede sobrecargar para aceptar un argumento CommandBehavior y modificar el comportamiento predeterminado de DataReader. Puede pasar al método ExecuteReader un argumento CommandBehavior.SequentialAccess para modificar el comportamiento predeterminado de DataReader de forma que en lugar de cargar los datos por filas, los vaya cargando secuencialmente a medida que los vaya recibiendo. Este sistema es idóneo para cargar BLOB y otras estructuras de datos grandes. Tenga en cuenta que este comportamiento puede variar en función del origen de datos. Por ejemplo, si se devuelve un BLOB desde Microsoft Access, el BLOB completo se cargará en memoria, en lugar de que los datos se carguen secuencialmente a medida que se reciben.

Al configurar DataReader para que utilice SequentialAccess debe tener en cuenta la secuencia en que va a tener acceso a los datos devueltos. El comportamiento predeterminado de DataReader consistente en cargar completamente una fila de datos en cuanto hay datos suficientes permite tener acceso a ellos en cualquier orden hasta que se lee la fila siguiente. Sin embargo, al utilizar SequentialAccess es necesario tener acceso a los diferentes campos que devuelve DataReader en el orden adecuado. Por ejemplo, si la consulta devuelve tres columnas y la tercera es un BLOB, debe devolver los valores de los campos primero y segundo antes de tener acceso a los datos BLOB del tercer campo. Si trata de tener acceso al tercer campo antes que al primero y segundo, puede que éstos dejen de estar disponibles. Esto se debe a que SequentialAccess cambia la forma en que el DataReader devuelve los datos, haciendo que lo haga de forma secuencial con lo que los datos dejan de estar disponibles en el momento en que el DataReader lee datos posteriores.

Cuando intente obtener acceso a los datos del campo BLOB, utilice los descriptores de acceso con información de tipos GetBytes o GetChars del DataReader, que llenan una matriz con los datos. En el caso de los datos de caracteres, puede utilizar también GetString; no obstante, si desea conservar los recursos del sistema, es mejor que no cargue un valor BLOB completo en una sola variable de cadena. Puede especificar un tamaño determinado de búfer para los datos que se van a devolver, así como la ubicación de comienzo para leer el primer byte o carácter de los datos devueltos. GetBytes y GetChars devuelven un valor de tipo long que representa el número de bytes o caracteres devueltos. Si pasa una matriz con valores null a GetBytes o GetChars, el valor de tipo long devuelto contiene el número total de bytes o caracteres del BLOB. También puede especificar un índice de la matriz como posición de comienzo para la lectura de datos.

En el ejemplo siguiente se devuelve el identificador y el logotipo del editor desde la base de datos de ejemplo pubs de Microsoft SQL Server. El identificador de editor (pub_id) es un campo con caracteres, mientras que el logotipo es una imagen de BLOB. Como el campo logo es un mapa de bits, el ejemplo devuelve datos binarios mediante GetBytes. Tenga en cuenta que la necesidad de tener acceso a los datos de forma secuencial hace que en la fila actual de datos se tenga acceso al identificador de editor antes que al logotipo.

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

Vea también

Utilizar proveedores de datos de .NET Framework para obtener acceso a datos | Escribir valores BLOB en una base de datos | OleDbDataReader (Clase) | OleDbCommand (Clase) | OdbcDataReader (Clase) | OdbcCommand (Clase) | SqlDataReader (Clase) | SqlCommand (Clase) | CommandBehavior (Enumeración)