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

如何用GZip高效实现首字节不压缩且无需额外MemoryStream?

实现首字节不压缩的GZip流式处理方案

需求与问题

我需要在网络发送大型数组前进行压缩,但首字节绝对不能被压缩。想解决两个问题:

  1. 用GZip能不能高效实现该需求——无需在压缩完成后创建额外的MemoryStream?
  2. 解压时计划先读取首字节,再将剩余内容视为压缩缓冲区,该如何操作?

原代码问题

原代码中首字节被写入了GZipStream,导致被压缩,不符合需求:

var compressedStream = new MemoryStream();
var zipStream = new GZipStream(compressedStream, System.IO.Compression.CompressionLevel.Optimal, true);

var w = new BinaryWriter(zipStream);

byte packetType = 5;
w.Write(packetType);   // <----- 这里被压缩了,不符合需求

while(hasMore){
   w.Write(someVars);
}

// 重要:先关闭再Seek()
zipStream.Close();
binaryWriter.Close();
compressedStream.Seek(0, SeekOrigin.Begin);

压缩端实现(无额外MemoryStream)

核心思路:先将首字节直接写入最终输出流,再把GZipStream附加到该流上处理后续需要压缩的内容,既保证首字节不被压缩,又全程复用同一个流,无额外内存开销。

修改后的代码:

var compressedStream = new MemoryStream();
// 1. 直接写入未压缩的首字节(不经过GZipStream)
using var rawWriter = new BinaryWriter(compressedStream);
byte packetType = 5;
rawWriter.Write(packetType);

// 2. 在同一个流上创建GZipStream,处理后续需压缩的数据
using var zipStream = new GZipStream(compressedStream, System.IO.Compression.CompressionLevel.Optimal, true);
using var zipWriter = new BinaryWriter(zipStream);

while (hasMore)
{
    zipWriter.Write(someVars); // 这部分数据会被压缩
}

// 确保压缩流的所有缓冲数据写入底层流
zipStream.Flush();
zipStream.Close();

// 将流指针重置到开头,准备发送
compressedStream.Seek(0, SeekOrigin.Begin);

关键说明:

  • 利用GZipStream的leaveOpen: true参数,关闭压缩流时不会关闭底层的MemoryStream,保证后续操作可继续。
  • 首字节直接写入底层流,完全不经过压缩逻辑,满足"绝对不被压缩"的要求。

解压端实现

核心思路:先读取流的第一个字节(未压缩的包类型),再将剩余流内容交给GZipStream解压,无需拆分流或创建副本。

代码示例:

// receivedStream为从网络接收的完整流
receivedStream.Seek(0, SeekOrigin.Begin);

// 1. 读取未压缩的首字节
using var rawReader = new BinaryReader(receivedStream);
byte packetType = rawReader.ReadByte();

// 2. 用GZipStream处理剩余的压缩内容
using var zipStream = new GZipStream(receivedStream, System.IO.Compression.CompressionMode.Decompress);
using var zipReader = new BinaryReader(zipStream);

// 读取解压后的数据,示例以ReadInt32为例,根据实际类型调整
while (receivedStream.Position < receivedStream.Length)
{
    var data = zipReader.ReadInt32();
    // 处理解压后的数据
}

关键说明:

  • 读取首字节后,流的指针会自动移动到剩余内容的起始位置,直接将该流传入GZipStream即可自动解压后续内容。
  • 无需额外创建MemoryStream拷贝压缩部分,直接复用接收流,效率更高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 23:45:40