C#中通过存储过程读取SQL Server存储的字节数组格式图片
从SqlDataReader读取可变长度二进制图片数据的实现
你不需要手动实现复杂的分块读取逻辑,以下两种经过验证的写法都可以正确读取任意长度的图片字节数组,适配SQL Server的varbinary(MAX)等二进制字段类型。
方法1:直接强转读取(推荐,代码最简洁)
ADO.NET 读取二进制列时,索引器会自动返回完整的byte[]类型结果,你只需要提前判断字段是否为DBNull即可,不需要手动处理字节长度,性能和手动调用GetBytes没有本质区别,是业务开发中最常用的写法:
// OverViewImage是返回结果的第5列,索引从0开始即序号为4 byte[]? overViewImage = null; int imageColumnIndex = 4; if (!reader.IsDBNull(imageColumnIndex)) { overViewImage = (byte[])reader[imageColumnIndex]; }
如果担心列序号和存储过程返回顺序不匹配,也可以用列名读取,写法容错性更高,性能损耗可以忽略:
int imgColIdx = reader.GetOrdinal("OverViewImage"); if (!reader.IsDBNull(imgColIdx)) { overViewImage = (byte[])reader[imgColIdx]; }
方法2:使用GetBytes方法手动读取
如果你明确要使用GetBytesAPI实现读取,可以先通过一次空缓冲区调用拿到字段的总字节长度,再初始化对应长度的数组完成一次性读取,适合对读取过程有自定义需求的场景:
byte[]? overViewImage = null; int imageColumnIndex = 4; if (!reader.IsDBNull(imageColumnIndex)) { // 传入null作为缓冲区,方法返回值就是该字段存储的总字节长度 long totalByteLength = reader.GetBytes(imageColumnIndex, 0, null, 0, 0); // 初始化和实际存储长度一致的字节数组 overViewImage = new byte[totalByteLength]; // 读取全部字节到数组中 reader.GetBytes(imageColumnIndex, 0, overViewImage, 0, (int)totalByteLength); }
如果存储的是单文件大小超过100MB的超大二进制数据,可以把缓冲区设置为固定大小(如8KB),循环调用GetBytes分块写入MemoryStream,避免一次性占用过多内存。车牌识别的抓拍图片通常体积在几MB以内,一次性读取即可。
完整循环赋值示例
替换你现有代码中while循环内的逻辑即可:
while (reader.Read()) { var entryDateTime = reader.GetDateTime(0); var plate = reader.GetString(1); var plaza = reader.GetString(2); var direction = reader.GetString(3); byte[]? overViewImage = null; int imgColIdx = 4; if (!reader.IsDBNull(imgColIdx)) { overViewImage = (byte[])reader[imgColIdx]; } var xList = new PlateNumberEntity { EntryDateTime = entryDateTime, PlateNumber = plate, Plaza = plaza, Direction = direction, OverViewImage = overViewImage }; list.Add(xList); }
注意事项
- 必须提前通过
IsDBNull判断字段值是否为空,否则数据库中存储NULL值时会触发类型转换异常 - 确保列序号和存储过程
GetAlprEntryInfo返回的字段顺序完全一致,用列名+GetOrdinal的写法可以避免存储过程字段顺序调整导致的取值错误
内容的提问来源于stack exchange,提问作者Ibanez1408
相关产品推荐
相关产品推荐

