我应该将什么'length'参数传递给SqlDataReader.GetBytes()

Mar*_*tyn 22 .net c# vb.net ado.net sqldatareader

我有一个SqlDataReader,需要使用SqlDataReader.GetBytes()方法从中读取varbinary(max)列.此方法填充字节数组,因此需要知道要读取的数据长度.

这是我感到困惑的地方.显然,我想读取从这行/列中的数据库返回的所有数据,那么我应该通过什么'length'参数?

据我所知,SqlDataReader没有提供任何方法来发现可用的数据长度,因此这种方法对我来说似乎相当尴尬.

我很想在这里传递int.MaxValue并忘记这个问题,但是有些事情并不适合我.

我知道我可以打电话

byte[] value = (byte[])dataReader["columnName"];
Run Code Online (Sandbox Code Playgroud)

..而这似乎完全在内部处理长度问题.但是,我正在使用一组围绕SqlDataReader.GetXXXX()方法构建的复杂代码生成模板.所以我被绑在使用GetBytes并需要了解它的正确用法.

Mar*_*ell 35

在处理时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
}
Run Code Online (Sandbox Code Playgroud)

然而!如果您使用的是中等大小的数据,那么您的原始代码:

byte[] data = (byte[])reader[col];
Run Code Online (Sandbox Code Playgroud)

很好!! .这种方法没有任何问题,实际上Get*API 在少数情况下被破坏 - 这GetChar()是一个值得注意的例子(提示:它不起作用).

不要紧,你有现有的使用代码Get*-在这种情况下,中投的做法是完全恰当的.

  • @Martyn不,你误解了我.循环是必需的,因为只返回10个字节是完全合法的,即使底层数据有100,000并且缓冲区有1000个空间.你必须循环因为**只知道你何时到达终点是继续阅读** (3认同)
  • @Martyn`ReadBytes`是一个流API; 你可以**永远不会**传递一个大的值,并假设它读取所有内容 - 你**总是**需要循环,直到你得到一个非正值.我在这里的主要猜测(未经检查)是*内部*它已经知道长度(至少在缓冲使用中),并且将分配一个正确大小的数组并且只是块数据复制.如果你通过`GetBytes()`来实现它,你需要将它写入`MemoryStream`然后在最后调用`ms.ToArray()`.问题在于:额外的(不必要的)`byte []`分配.由你决定是否有问题. (2认同)