如何在C#中复现SQL Server的Compress函数功能?
解决C#压缩数据后SQL DECOMPRESS解压乱码问题
问题原因
乱码的核心原因是编码不匹配:
- SQL中
COMPRESS(N'xxx')是对**UTF-16(Unicode)**编码的字节流进行压缩(N前缀表示NVARCHAR类型,对应UTF-16LE编码)。 - 你的C#代码用
Encoding.UTF8.GetBytes将字符串转为UTF-8字节后再压缩,导致SQL的DECOMPRESS函数解压得到的是UTF-8字节,但默认转为NVARCHAR(UTF-16)时就会出现乱码。
解决方案
根据需求,有两种可行的修复方式:
方式一:和SQL COMPRESS(N'...')完全对齐(推荐)
修改C#代码中的编码转换,将字符串转为UTF-16字节(和SQL的NVARCHAR一致),再进行压缩:
private readonly string _insertQuery = @"INSERT INTO Player([Name],[Surname],[Info]) OUTPUT INSERTED.Id, inserted.Info VALUES(?,?,?)"; public void CompressAndWriteToDB() { using OleDbConnection connection = new(_connectionString); OleDbCommand cmd = new OleDbCommand(); cmd.CommandType = CommandType.Text; cmd.CommandText = _insertQuery; cmd.Parameters.Add(new OleDbParameter("@name", "John")); cmd.Parameters.Add(new OleDbParameter("@surname", "Smith")); var uncompressedString = "{\"sport\":\"Basketball\",\"age\": 45,\"rank\":1,\"points\":15258, \"turn\":17}"; // 修正JSON语法错误 // 改用UTF-16编码(对应SQL的NVARCHAR) var bytes = Encoding.Unicode.GetBytes(uncompressedString); using (var memoryStream = new MemoryStream()) { using (var gzipStream = new GZipStream(memoryStream, CompressionLevel.Optimal)) { gzipStream.Write(bytes, 0, bytes.Length); } // 改用OleDbType对应类型,更规范 var param = cmd.Parameters.Add("@info", OleDbType.VarBinary); param.Value = memoryStream.ToArray(); } cmd.Connection = connection; connection.Open(); cmd.ExecuteReader(); }
此时在SSMS中用原语句即可正常解压:
SELECT Name, Surname, CAST(DECOMPRESS(Info) AS NVARCHAR(MAX)) AS Info FROM Player
方式二:保持UTF-8编码,修改SQL解压语句
如果希望在C#中继续使用UTF-8编码压缩,那么需要在SQL解压时指定UTF-8编码(代码页65001):
SELECT Name, Surname, CONVERT(VARCHAR(MAX), DECOMPRESS(Info), 65001) AS Info FROM Player
注意:此方式要求SQL Server版本支持UTF-8(2019及以上,或数据库兼容性级别150+)。
额外注意事项
- 修复了你代码中JSON字符串的语法错误:
"turn":17前多了一个逗号,修正后JSON格式才合法。 - 使用OleDb时,参数类型建议用
OleDbType.VarBinary而非SqlDbType.VarBinary,保持组件类型一致。
内容的提问来源于stack exchange,提问作者McCrockett
相关产品推荐
相关产品推荐

