gzip.compress()和gzip.decompress()适用于小数据内存压缩,因需一次性加载全部数据,处理大文件易致OOM;仅支持bytes类型输入,compresslevel参数范围为0–9(默认6)。

gzip.compress() 和 gzip.decompress() 适合小数据流,但别直接喂大文件
这两个函数最常用,但它们要求整个输入必须能一次性装进内存。比如你用 gzip.compress(b"hello world") 没问题,但若想压缩一个 2GB 的日志流,用它就会 OOM。
常见错误现象:MemoryError 或进程被系统 kill;实际场景中多见于读取网络响应体、数据库 BLOB 字段或临时生成的大量 JSON 后立即压缩。
- 只对
bytes类型输入有效,传str会报TypeError: a bytes-like object is required - 压缩级别用
compresslevel=9(默认是 6),但 >9 无效,ValueError - 它们不处理文件头校验和(如 CRC32),也不写 gzip 文件格式元信息——纯压缩/解压字节流,不是生成 .gz 文件
用 gzip.GzipFile 处理任意长度的流,关键在 mode 和 fileobj
真正做流式压缩/解压得靠 GzipFile,但它不直接操作路径,而是依赖已打开的可读/可写类文件对象(file-like object)。很多人卡在这一步:误以为它能自动打开文件,其实不能。
典型使用场景:从 requests.Response.raw 读响应流并实时解压;把 io.BytesIO 当作中间缓冲区做管道式处理。
立即学习“Python免费学习笔记(深入)”;
- 压缩流:创建
GzipFile(mode="w", fileobj=buffer),然后.write()多次,最后.close()—— 不 close 就丢数据 - 解压流:用
GzipFile(mode="r", fileobj=buffer),再调.read()或循环.read(8192) -
fileobj必须支持read()/write(),且是 binary 模式;用open("x.gz", "rb")得到的文件对象可以直接传
配合 io.BytesIO 实现内存中流式中转
当没有真实文件、又不想全量加载时,BytesIO 是最常用的“虚拟文件”。但注意它的位置指针(cursor)行为:写完不重置,后续读就是空。
示例:把一段文本压缩进 BytesIO,再解出来
import gzip import io <p>buf = io.BytesIO() with gzip.GzipFile(fileobj=buf, mode="w") as gzf: gzf.write(b"some data")</p><p>buf.seek(0) # ← 这步不能少!否则 read() 返回空字节 with gzip.GzipFile(fileobj=buf, mode="r") as gzf: data = gzf.read() # b"some data"</p>
- 写入后必须
buf.seek(0),否则解压器从末尾开始读 - 如果只是单次压缩+解压,用
gzip.compress()/decompress()更简洁;只有需要分块读写、或衔接其他流处理器(如zlib或加密流)时才上GzipFile -
BytesIO本身不压缩,只是容器;真正的压缩发生在GzipFile.write()调用时
解压未知来源的 gzip 流时,优先用 gzip.open() + error handling
如果你拿到的是一个可能损坏、或非标准 gzip 格式的字节流(比如某些嵌入式设备返回的截断流),直接用 GzipFile 容易抛 OSError: Not a gzipped file 或更隐蔽的 zlib.error。这时推荐先试 gzip.open(),它内部做了更多格式探测和容错。
-
gzip.open()默认按文件语义工作,但传io.BytesIO也能用:例如gzip.open(buf, "rb") - 加
errors="ignore"不生效(gzip 模块不支持该参数),真要容错得自己捕获zlib.error或OSError - 若流开头缺 magic bytes(
b"\x1f\x8b"),gzip.open()会立刻失败;而GzipFile可能延迟到第一次read()才报错
流式 gzip 处理真正的难点不在 API 调用,而在控制 buffer 生命周期、游标位置和错误传播边界——尤其当多个 GzipFile 嵌套或与 zlib 手动对接时,漏掉一次 close() 或 seek() 就会导致静默失败。


















