C# .NET如何基于大文件流指定片段创建GZipStream降低内存占用
实现方案
你不需要把目标压缩段全部加载到内存,只需要通过自定义的长度限制包装流封装FileStream即可实现流式读取解压:
步骤1:实现长度限制的包装流
这个流的作用是包装原始FileStream,限制最多只能读取指定长度的字节,避免GZipStream读取到超出目标压缩段的内容:
public class BoundedReadStream : Stream { private readonly Stream _innerStream; private long _remainingBytes; public BoundedReadStream(Stream innerStream, long maxReadLength) { _innerStream = innerStream ?? throw new ArgumentNullException(nameof(innerStream)); _remainingBytes = maxReadLength; if (!innerStream.CanRead) throw new ArgumentException("传入的流必须支持读取", nameof(innerStream)); } public override int Read(byte[] buffer, int offset, int count) { if (_remainingBytes <= 0) return 0; var bytesToRead = (int)Math.Min(count, _remainingBytes); var bytesRead = _innerStream.Read(buffer, offset, bytesToRead); _remainingBytes -= bytesRead; return bytesRead; } // 以下属性和方法按需实现,GZipStream仅依赖读相关的核心实现 public override bool CanRead => true; public override bool CanSeek => false; public override bool CanWrite => false; public override long Length => throw new NotSupportedException(); public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } public override void Flush() => throw new NotSupportedException(); public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException(); public override void SetLength(long value) => throw new NotSupportedException(); public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); }
步骤2:调整解压逻辑
直接操作FileStream,不需要中间转存MemoryStream:
// 打开文件流 using FileStream fileStream = new FileStream("你的文件路径", FileMode.Open, FileAccess.Read); // 定位到压缩数据的起始地址 fileStream.Position = 你要的压缩数据起始地址; // 用长度限制流包装,只允许读取指定长度的压缩数据 using BoundedReadStream boundedStream = new BoundedReadStream(fileStream, 你要的压缩数据长度); // 直接传入GZipStream解压 using GZipStream gZipStream = new GZipStream(boundedStream, CompressionMode.Decompress); // 后续直接从gZipStream流式读取解压后的数据即可,全程不会加载全量压缩数据到内存 // 示例:把解压后的数据写入到目标文件 // using var outputFs = File.Create("解压后输出路径"); // gZipStream.CopyTo(outputFs);
注意事项
- 请确保你指定的起始地址到结束地址之间的内容是完整的GZip格式压缩数据,否则会抛出解压异常
- 该方案内存占用仅为读写缓冲区默认大小(通常是4KB),适合处理GB级以上的大容量压缩段
内容的提问来源于stack exchange,提问作者S41L0R
相关产品推荐
相关产品推荐

