Какой параметр длины нужно передать в SqlDataReader.GetBytes()
У меня есть SqlDataReader и вам нужно прочитать столбец varbinary (max), используя метод SqlDataReader.GetBytes(). Этот метод заполняет массив байтов и поэтому должен знать, какую длину данных читать.
Вот где я запутался. Ясно, что я хочу прочитать все данные, которые были возвращены из базы данных в этой строке/столбце, и какой параметр "длины" должен пройти?
Насколько я вижу, SqlDataReader не предоставляет каких-либо методов для определения того, какая длина данных доступна, поэтому этот метод кажется мне довольно неудобным.
У меня возникает соблазн просто передать int.MaxValue здесь и забыть о проблеме, но что-то об этом не подходит мне.
Я знаю, что вместо этого я могу позвонить
byte[] value = (byte[])dataReader["columnName"];
.. и это, кажется, полностью заботится о проблеме длины внутри. Однако я работаю с набором сложных шаблонов генерации кода, которые были построены вокруг методов SqlDataReader.GetXXXX(). Поэтому я привязан к использованию GetBytes и должен понимать его правильное использование.
Ответы
Ответ 1
При работе с varbinary(max)
существует два сценария:
- длина данных умеренная
- длина данных большая
GetBytes()
предназначен для сценария второй, когда вы используете CommandBehaviour.SequentialAccess
для обеспечения потоковой передачи данных, а не для буферизации. В частности, в этом использовании вы обычно пишете (например) в потоке в цикле. Например:
// moderately sized buffer; 8040 is a SQL Server page, note
byte[] buffer = new byte[8040];
long offset = 0;
int read;
while((read = reader.GetBytes(col, offset, buffer, 0, buffer.Length)) > 0) {
offset += read;
destination.Write(buffer, 0, read); // push downstream
}
Однако! Если вы используете данные умеренного размера, то ваш исходный код:
byte[] data = (byte[])reader[col];
отлично!. Нет ничего плохого в этом подходе, и на самом деле API-интерфейс Get*
в некоторых случаях разбит на несколько случаев - GetChar()
- заметный пример (подсказка: он не работает).
Не имеет значения, что у вас есть существующий код, который использует Get*
- в этом случае подход отливки идеально подходит.
Ответ 2
Вы могли бы это сделать. Найдено на MSDN. Вероятно, это может служить вашей целью
// 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();
http://msdn.microsoft.com/en-us/library/87z0hy49%28v=vs.71%29.aspx#Y132
Или этот
int ndx = rdr.GetOrdinal("<ColumnName>");
if(!rdr.IsDBNull(ndx))
{
long size = rdr.GetBytes(ndx, 0, null, 0, 0); //get the length of data
byte[] values = new byte[size];
int bufferSize = 1024;
long bytesRead = 0;
int curPos = 0;
while (bytesRead < size)
{
bytesRead += rdr.GetBytes(ndx, curPos, values, curPos, bufferSize);
curPos += bufferSize;
}
}