如何用GZip高效实现首字节不压缩且无需额外MemoryStream?
实现首字节不压缩的GZip流式处理方案
需求与问题
我需要在网络发送大型数组前进行压缩,但首字节绝对不能被压缩。想解决两个问题:
- 用GZip能不能高效实现该需求——无需在压缩完成后创建额外的MemoryStream?
- 解压时计划先读取首字节,再将剩余内容视为压缩缓冲区,该如何操作?
原代码问题
原代码中首字节被写入了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
相关产品推荐
相关产品推荐

