Поделиться через


Получение двоичных данных

По умолчанию DataReader загружает входящие данные в виде строки, как только доступна вся строка данных. Однако двоичные большие объекты (BLOB-объекты) требуют другого лечения, так как они могут содержать гигабайты данных, которые не могут содержаться в одной строке. Метод Command.ExecuteReader имеет перегрузку, которая принимает CommandBehavior аргумент для изменения поведения по умолчанию DataReader. Вы можете передать SequentialAccess в метод ExecuteReader, чтобы изменить поведение DataReader по умолчанию, так чтобы вместо загрузки строк данных он загружал данные последовательно по мере их поступления. Это идеально подходит для загрузки BLOB-объектов или других крупных структур данных. Обратите внимание, что это поведение может зависеть от источника данных. Например, при возврате BLOB-объекта из Microsoft Access весь BLOB будет загружен в память сразу, а не последовательно по мере получения.

При настройке DataReader для использования SequentialAccess важно отметить последовательность, в которой вы обращаетесь к возвращаемым полям. Поведение dataReader по умолчанию, которое загружает всю строку сразу после его доступности, позволяет получить доступ к полям, возвращаемым в любом порядке, пока следующая строка не будет прочитана. Однако при использовании SequentialAccess необходимо обращаться к полям, возвращаемым DataReader, в заданной последовательности. Например, если ваш запрос возвращает три столбца, третий из которых — это BLOB, сначала необходимо вернуть значения первых двух полей перед доступом к данным BLOB в третьем поле. Если вы обращаетесь к третьему полю перед первым или вторым полями, значения первого и второго полей больше не доступны. Это связано с тем, что SequentialAccess изменил DataReader таким образом, чтобы данные возвращались в последовательном порядке, и после того, как DataReader прошёл вперёд, они становятся недоступными.

При доступе к данным в поле BLOB используйте типизированные аксессоры GetBytes или GetChars из объекта DataReader, которые заполняют массив данными. Вы также можете использовать GetString для символьных данных; однако. Чтобы сохранить системные ресурсы, может потребоваться не загрузить целое значение BLOB в одну строковую переменную. Вместо этого можно указать определенный размер возвращаемых данных буфера и начальное расположение для первого байта или символа, считываемого из возвращаемых данных. GetBytes и GetChars возвращают long значение, представляющее количество возвращаемых байтов или символов. Если передать пустой массив в GetBytes или GetChars, возвращаемое длинное значение будет общим числом байтов или символов в BLOB. При необходимости можно указать индекс в массиве в качестве начальной позиции для считываемых данных.

Пример

В следующем примере возвращается идентификатор издателя и логотип из примера базы данных pubs в Microsoft SQL Server. Идентификатор издателя (pub_id) — это символьное поле, а логотип — это изображение, которое является BLOB. Так как поле логотипа является растровым изображением, в примере возвращаются двоичные данные с помощью GetBytes. Обратите внимание, что к идентификатору издателя получают доступ для текущей строки данных перед логотипом, так как доступ к полям должен осуществляться последовательно.

' Assumes that connection is a valid SqlConnection object.  
Dim command As SqlCommand = New SqlCommand( _  
  "SELECT pub_id, logo FROM pub_info", connection)  
  
' Writes the BLOB to a file (*.bmp).  
Dim stream As FileStream
' Streams the binary data to the FileStream object.  
Dim writer As BinaryWriter
' The size of the BLOB buffer.  
Dim bufferSize As Integer = 100
' The BLOB byte() buffer to be filled by GetBytes.  
Dim outByte(bufferSize - 1) As Byte
' The bytes returned from GetBytes.  
Dim retval As Long
' The starting position in the BLOB output.  
Dim startIndex As Long = 0
  
' The publisher id to use in the file name.  
Dim pubID As String = ""
  
' Open the connection and read data into the DataReader.  
connection.Open()  
Dim reader As SqlDataReader = command.ExecuteReader(CommandBehavior.SequentialAccess)  
  
Do While reader.Read()  
  ' Get the publisher id, which must occur before getting the logo.  
  pubID = reader.GetString(0)  
  
  ' Create a file to hold the output.  
  stream = New FileStream( _  
    "logo" & pubID & ".bmp", FileMode.OpenOrCreate, FileAccess.Write)  
  writer = New BinaryWriter(stream)  
  
  ' Reset the starting byte for a new BLOB.  
  startIndex = 0  
  
  ' Read bytes into outByte() and retain the number of bytes returned.  
  retval = reader.GetBytes(1, startIndex, outByte, 0, bufferSize)  
  
  ' Continue while there are bytes beyond the size of the buffer.  
  Do While retval = bufferSize  
    writer.Write(outByte)  
    writer.Flush()  
  
    ' Reposition start index to end of the last buffer and fill buffer.  
    startIndex += bufferSize  
    retval = reader.GetBytes(1, startIndex, outByte, 0, bufferSize)  
  Loop  
  
  ' Write the remaining buffer.  
  writer.Write(outByte, 0 , retval - 1)  
  writer.Flush()  
  
  ' Close the output file.  
  writer.Close()  
  stream.Close()  
Loop  
  
' Close the reader and the connection.  
reader.Close()  
connection.Close()  
// Assumes that connection is a valid SqlConnection object.  
SqlCommand command = new SqlCommand(  
  "SELECT pub_id, logo FROM pub_info", connection);  
  
// Writes the BLOB to a file (*.bmp).  
FileStream stream;
// Streams the BLOB to the FileStream object.  
BinaryWriter writer;
  
// Size of the BLOB buffer.  
int bufferSize = 100;
// The BLOB byte[] buffer to be filled by GetBytes.  
byte[] outByte = new byte[bufferSize];
// The bytes returned from GetBytes.  
long retval;
// The starting position in the BLOB output.  
long startIndex = 0;
  
// The publisher id to use in the file name.  
string pubID = "";
  
// Open the connection and read data into the DataReader.  
connection.Open();  
SqlDataReader reader = command.ExecuteReader(CommandBehavior.SequentialAccess);  
  
while (reader.Read())  
{  
  // Get the publisher id, which must occur before getting the logo.  
  pubID = reader.GetString(0);
  
  // Create a file to hold the output.  
  stream = new FileStream(  
    "logo" + pubID + ".bmp", FileMode.OpenOrCreate, FileAccess.Write);  
  writer = new BinaryWriter(stream);  
  
  // Reset the starting byte for the new BLOB.  
  startIndex = 0;  
  
  // Read bytes into outByte[] and retain the number of bytes returned.  
  retval = reader.GetBytes(1, startIndex, outByte, 0, bufferSize);  
  
  // Continue while there are bytes beyond the size of the buffer.  
  while (retval == bufferSize)  
  {  
    writer.Write(outByte);  
    writer.Flush();  
  
    // Reposition start index to end of last buffer and fill buffer.  
    startIndex += bufferSize;  
    retval = reader.GetBytes(1, startIndex, outByte, 0, bufferSize);  
  }  
  
  // Write the remaining buffer.  
  writer.Write(outByte, 0, (int)retval);  
  writer.Flush();  
  
  // Close the output file.  
  writer.Close();  
  stream.Close();  
}  
  
// Close the reader and the connection.  
reader.Close();  
connection.Close();  

См. также