如何在C#中突破SqlDataReader.GetBytes的8000字节限制?
如何在C#中突破SqlDataReader.GetBytes的8000字节限制?
嗨,我之前也踩过这个坑!其实这个8000字节的限制并不是GetBytes本身的问题,而是你的用法或者查询环节出了小疏漏,咱们一步步来搞定它:
先排查核心原因
首先确认你的数据库列类型:如果是旧的image类型还能用,但更推荐用varbinary(max)(毕竟image已经被微软标记为过时了)。另外一定要检查你的查询语句——千万别对attachment_data字段做多余的转换(比如CAST(attachment_data AS VARCHAR(8000))),这种操作会直接把数据截断到8000字节!
正确的GetBytes用法:循环分块读取
GetBytes本身是支持读取大字段的,它的设计逻辑就是分块读取,你之前只调用了一次,自然只能拿到部分数据。下面给你两种可靠的实现方式:
方式1:先拿总长度再一次性读取
如果你的内存足够容纳整个文件,可以先获取字段的总字节数,再创建对应大小的数组读取:
byte[] byteArray = null; using (sqlCmd = new SqlCommand(strQuery, sqlConn)) { using (var sqlDataRead = sqlCmd.ExecuteReader()) { while (sqlDataRead.Read()) { int colOrdinal = sqlDataRead.GetOrdinal("attachment_data"); // 获取字段的总字节数 long totalBytes = sqlDataRead.GetBytes(colOrdinal, 0, null, 0, 0); byteArray = new byte[totalBytes]; long bytesRead = 0; // 循环读取直到获取全部数据 while (bytesRead < totalBytes) { bytesRead += sqlDataRead.GetBytes(colOrdinal, bytesRead, byteArray, (int)bytesRead, (int)(totalBytes - bytesRead)); } } } } // 写入磁盘文件 if (byteArray != null) { File.WriteAllBytes(@"C:\your\target\path\file.tif", byteArray); }
方式2:用MemoryStream分块读取(更省内存)
如果文件特别大,用MemoryStream分块读取更稳妥,避免一次性占用过多内存:
using (sqlCmd = new SqlCommand(strQuery, sqlConn)) { using (var sqlDataRead = sqlCmd.ExecuteReader()) { while (sqlDataRead.Read()) { int colOrdinal = sqlDataRead.GetOrdinal("attachment_data"); using (MemoryStream ms = new MemoryStream()) { byte[] buffer = new byte[8192]; // 用8KB的缓冲区,大小可以按需调整 long offset = 0; long bytesRead; // 循环读取直到没有数据 while ((bytesRead = sqlDataRead.GetBytes(colOrdinal, offset, buffer, 0, buffer.Length)) > 0) { ms.Write(buffer, 0, (int)bytesRead); offset += bytesRead; } // 转成字节数组并写入文件 byte[] byteArray = ms.ToArray(); File.WriteAllBytes(@"C:\your\target\path\file.tif", byteArray); } } } }
额外注意事项
- 确保数据库连接字符串里没有设置限制数据读取的参数(比如
Packet Size太小,一般默认值就够用)。 - 验证数据库里的原始数据是否完整:可以在SQL Server里执行
SELECT DATALENGTH(attachment_data) FROM your_table,看看返回的长度和你预期的文件大小是否一致,如果不一致,那问题出在数据存储环节,不是读取的问题。
备注:内容来源于stack exchange,提问作者Cassfutbol
相关产品推荐
相关产品推荐

