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

GZipStream解压数据异常求助:压缩后解压长度不一致

问题出在GZipStream的压缩收尾步骤上!

嘿,我一眼就看穿问题所在了——你没有正确完成GZipStream的压缩流程,导致压缩后的数据流不完整,解压自然得不到和原数据一样的长度。

为什么会这样?

GZipStream在压缩时会把数据暂存到内部缓冲区,只有缓冲区满或者明确触发收尾操作时,才会把所有压缩数据(包括GZip格式必须的结束标记)写入目标流。你现在只调用了Flush(),它只会把当前缓冲区的内容刷到ms2,但不会写入结束标记——而这个标记是解压时识别压缩数据完整性的关键,缺少它的话,解压过程会提前终止,自然就得不到完整的原始数据了。

修正后的代码

用using语句包裹GZipStream是最稳妥的方式,它会在代码块结束时自动调用Dispose(),而Dispose()内部会帮你完成FlushFinalBlock()(收尾压缩)的操作,同时还能保证即使出现异常也会正确释放资源:

// Serialize
var ms = new MemoryStream();
ProtoBuf.Serializer.Serialize(ms, result);
ms.Seek(0, SeekOrigin.Begin);

// Compress - 使用using自动处置流,完成压缩收尾
var ms2 = new MemoryStream();
using (var zipStream = new GZipStream(ms2, CompressionMode.Compress, leaveOpen: true))
{
    ms.CopyTo(zipStream);
} // 此处自动调用Dispose,写入GZip结束标记
ms2.Seek(0, SeekOrigin.Begin);

// Test
var ms3 = new MemoryStream();
using (var unzipStream = new GZipStream(ms2, CompressionMode.Decompress))
{
    unzipStream.CopyTo(ms3);
}
System.Diagnostics.Debug.WriteLine($"{ms.Length} =? {ms3.Length}");

关键细节说明

  • leaveOpen: true参数很重要:它告诉GZipStream在Dispose时不要关闭ms2,这样我们后续还能继续操作这个内存流。
  • 如果你不想用using,也可以手动调用zipStream.FlushFinalBlock()替代Flush(),但一定要在ms.CopyTo(zipStream)之后调用,然后再关闭zipStream。不过using是更推荐的C#最佳实践,能避免遗漏资源释放。

现在再运行代码,你应该就能看到压缩前后的长度完全一致啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 06:36:50