2011-03-20 48 views
33

Tengo una tabla llamada Blob (Id (int), Data (Image)). Necesito usar SqlDataReader para obtener esos datos de imagen. Tenga en cuenta que no quiero Response.Binarywrite() los datos en el navegador. Solo necesito esos datos binarios como byte [] para usarlos en algunas operaciones internas. La única forma en que puedo pensar es en obtener una identificación usando SqlDataReader y otra vez usar SqlCommand.ExecuteScalar() para obtenerlo como byte [] para una identificación dada. ¿Puedo usar solo SqlDataReader (SqlCommand.ExecuteReader) para obtener esos datos de imagen como byte []? ¿Me estoy perdiendo algo?Obteniendo datos binarios usando SqlDataReader

Respuesta

57

Usted debe poder conseguirlo vía: (byte[])reader.Items["Data"].

También tenga en cuenta que el tipo de datos image está en desuso, y se eliminará en una versión futura de SQL Server; use varbinary(max) en su lugar.

+17

Aún más corto: '(byte []) reader [" Data "]' – Cosmin

+2

Ni siquiera veo una colección 'Items' en' SqlDataReader' en .NET 4.0. – Zack

+0

¿Está obsoleta la recolección de elementos? –

16

Sí, puede usar SqlDataReader.GetBytes. Es probable que desee pasar null para el búfer en la primera llamada, para averiguar la cantidad de datos que hay, y luego llamar de nuevo con un búfer de tamaño adecuado.

puede simplemente ser capaz de utilizar el indexador y arrojar el resultado a una matriz de bytes - No estoy seguro. Vale la pena intentarlo :)

+1

ind ndx = rdr.GetOrdinal (""); if (! Rdr.IsDBNull (ndx)) { long size = rdr.GetBytes (ndx, 0, null, 0, 0); // obtener la longitud de los datos byte [] values ​​= new byte [size]; int bufferSize = 1024; bytes largosRead = 0; int curPos = 0; while (bytesRead

+0

@ydobonmai: ¿Por qué molestarse con un tamaño de búfer diferente cuando ya tiene un búfer del tamaño correcto? Y deberías usar 'bytesRead' en lugar de' curPos'; en este momento siempre asumes que lee una cantidad de buffer completa. –

+0

SqlDataReader.GetBytes() suena como un método muy eficiente ya que puede reutilizar la misma matriz (si tiene el tamaño adecuado). Por lo tanto, no cree una nueva matriz para cada columna como lo haría (byte []) reader ["Data"]. – mmmmmmmm

7

De MSDN. No estoy seguro de por qué no pude encontrar eso antes.

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. 
     if(retval > 0) // if file size can divide to buffer size 
      bw.Write(outbyte, 0, (int)retval); //original MSDN source had retval-1, a bug 
     bw.Flush(); 

     // Close the output file. 
     bw.Close(); 
     fs.Close(); 
    } 

    // Close the reader and the connection. 
    myReader.Close(); 
    pubsConn.Close(); 
+4

Una nota sobre esto: si no configura CommandBehavior.Acceso secuencial en la llamada ExecuteReader (por ejemplo, obtener el lector de otra parte de una capa de datos), hará cosas horribles para la memoria (creando una matriz de bytes del tamaño de una burbuja para cada llamada a GetBytes()); Esta solución SÓLO debe usarse con CommandBehavior.SequentialAccess como se demuestra aquí. – Tao

+1

¿Alguien podría ofrecer comentarios sobre cómo se decide el tamaño del búfer? El ejemplo usa 100, pero ¿por qué no 10 y por qué no 10,000? ¿Cuáles son los factores que uno debe considerar? –

1

No es necesario utilizar el lector. Simplemente use un conjunto de datos para obtener valores de la base de datos (usando Proc almacenado o cualquier otro método) y simplemente escriba cast with byte (código debajo) y guárdelo en una matriz de bytes. Tu trabajo está hecho.

byte[] productImage; 
productImage = (byte[])ds.Tables[0].Rows[0]["Image"]; 
9

En .NET Framework 4.5 se puede utilizar GetStream método para acceder a los datos binarios como corriente.

0

Utilice esta función para bytes seguros y flexibles de lectura:

/// <summary> 
    /// Reads all available bytes from reader 
    /// </summary> 
    /// <param name="reader"></param> 
    /// <param name="ordinal"></param> 
    /// <returns></returns> 
    private byte[] GetBytes(SqliteDataReader reader, int ordinal) 
    { 
     byte[] result = null; 

     if (!reader.IsDBNull(ordinal)) 
     { 
      long size = reader.GetBytes(ordinal, 0, null, 0, 0); //get the length of data 
      result = new byte[size]; 
      int bufferSize = 1024; 
      long bytesRead = 0; 
      int curPos = 0; 
      while (bytesRead < size) 
      { 
       bytesRead += reader.GetBytes(ordinal, curPos, result, curPos, bufferSize); 
       curPos += bufferSize; 
      } 
     } 

     return result; 
    }