You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 16:40:24