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

.NET 6 ZlibStream压缩解压后数据大小不一致问题排查

.NET 6 ZlibStream压缩解压后数据大小不一致问题排查

问题描述

使用.NET 6的ZlibStream处理数据压缩时,压缩后立即解压得到的数据与原始数据大小不一致。此前使用MiniZ依赖时数据大小正常,重构移除MiniZ后出现该问题。

原代码实现

压缩解压工具类:

public static class ZLib
{
    public static byte[] CompressData(Stream inStream, CompressionLevel level = CompressionLevel.Optimal)
    {
        using (var outStream = new MemoryStream())
        {
            using (var compressStream = new ZLibStream(outStream, level, false) )
            {
                inStream.CopyTo(compressStream);
                return outStream.ToArray();
            }
        }
    }

    public static byte[] DecompressData(Stream inStream)
    {
        using (var outStream = new MemoryStream())
        {
            using (var decompressStream = new ZLibStream(inStream, CompressionMode.Decompress))
            {
                decompressStream.CopyTo(outStream);
            }
            return outStream.ToArray();
        }
    }

    public static byte[] CompressData(byte[] inData, CompressionLevel compressionLevel = CompressionLevel.Optimal)
    {
        using (var inStream = new MemoryStream(inData, false))
            return CompressData(inStream, compressionLevel);
    }

    public static byte[] DecompressData(byte[] inData)
    {
        using (var inStream = new MemoryStream(inData, false))
            return DecompressData(inStream);
    }
}

使用方式:

private byte[] _texture32Data = ...;
//...//
byte[] texture32Compressed = ZLib.CompressData(_texture32Data, compressionLevel);
var texture32UncompressedSize = _texture32Data.Length;
var uncompressed = ZLib.DecompressData(texture32Compressed);
Debug.Assert(uncompressed.Length == texture32UncompressedSize); // 断言触发

断言失败的数值:

uncompressed.Length = 10153463
texture32UncompressedSize = 10223616

问题原因

核心错误在于压缩流未完成收尾操作就提前读取输出流:

  • 在CompressData方法中,return outStream.ToArray()语句写在ZLibStream的using块内部,此时ZLibStream尚未执行Dispose操作。
  • ZLibStream需要在Dispose时才会完成压缩的收尾工作(包括写入压缩结束标记、刷新缓冲区中剩余的压缩数据到输出流)。提前读取会导致输出流中的压缩数据不完整,解压后自然得到不完整的原始数据。

修复方案

有两种可行的修复方式:

方式1:将return语句移到ZLibStream的using块外部

利用using块自动调用Dispose的特性,确保压缩流完成所有数据写入后再读取输出流:

public static byte[] CompressData(Stream inStream, CompressionLevel level = CompressionLevel.Optimal)
{
    using (var outStream = new MemoryStream())
    {
        using (var compressStream = new ZLibStream(outStream, level, false))
        {
            inStream.CopyTo(compressStream);
        } // 此处ZLibStream自动Dispose,完成压缩收尾
        return outStream.ToArray();
    }
}

方式2:手动调用FlushFinalBlock()触发压缩收尾

在数据复制完成后,手动调用FlushFinalBlock()强制将所有剩余压缩数据写入输出流:

public static byte[] CompressData(Stream inStream, CompressionLevel level = CompressionLevel.Optimal)
{
    using (var outStream = new MemoryStream())
    {
        using (var compressStream = new ZLibStream(outStream, level, false))
        {
            inStream.CopyTo(compressStream);
            compressStream.FlushFinalBlock(); // 手动完成压缩收尾
            return outStream.ToArray();
        }
    }
}

验证说明

修复后,压缩生成的数据是完整的,解压后的字节数组长度将与原始数据完全一致,断言不再触发。此前MiniZ正常是因为其API实现会自动完成压缩数据的完整写入,无需依赖流的Dispose操作。


内容的提问来源于stack exchange,提问作者user3001150

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 06:23:28