首页
/ CPython gzip 模块完全指南:GzipFile、open/compress/decompress API 与 python -m gzip 命令行压缩解压

CPython gzip 模块完全指南:GzipFile、open/compress/decompress API 与 python -m gzip 命令行压缩解压

2026-09-07 09:21:38作者:薛曦旖Francesca

本篇指南围绕 CPython 标准库中的 gzip 模块展开,系统讲解其面向 gzip 格式(RFC 1952)的压缩与解压接口:gzip.open()GzipFile 类、compress()/decompress() 便捷函数,以及 python -m gzip 命令行工具。文中不仅完整梳理各 API 的参数语义、默认值与版本演进,还结合 Lib/gzip.py 源码与 Lib/test/test_gzip.py 测试用例,揭示 gzip 头部写入、CRC 校验、多成员(multi-member)处理等底层机制,帮助读者写出正确、可复现且性能合理的 gzip 压缩/解压代码。

gzip 模块是什么

gzip 模块为压缩与解压 gzip 格式文件提供了一组简单的接口,使用体验与 GNU 的 gzip/gunzip 程序一致:数据压缩由标准库的 zlib 模块承担(相关文档见 Doc/library/zlib.rst)。模块对外暴露:

  • GzipFile 类:读写 gzip 格式文件,自动完成压缩/解压,使其看起来就是一个普通的 file object;
  • open()compress()decompress() 三个便捷函数。

需要说明的是:gzip 属于 optional module,若你的 CPython 发行版缺少该模块(通常意味着缺少底层 zlib 支持),请查阅你的发行商提供的文档,说明见 Doc/includes/optional-module.rst。此外,gzip/gunzip 程序还能解压 compresspack 等工具生成的其他格式,这些格式本模块并不支持。

从当前仓库的源码布局看,gzip 的核心实现位于 Lib/gzip.py,其模块级 API 定义为 __all__ = ["BadGzipFile", "GzipFile", "open", "compress", "decompress"]Lib/gzip.py);底层流工具(GzipFile 继承的 BaseStream_GzipReader 继承的 DecompressReader 等)则抽取到 Lib/compression/_common/_streams.py 中供 bz2lzma 等压缩模块共享。

模块级 API 总览

名称 类型 用途
gzip.open(filename, mode='rb', compresslevel=6, encoding=None, errors=None, newline=None, *, mtime=None) 函数 以二进制或文本模式打开 gzip 压缩文件,返回 file object
gzip.GzipFile(...) 低层二进制读写类,模拟 file object(不支持 truncate()
gzip.compress(data, compresslevel=6, *, mtime=0) 函数 一次性压缩内存中的 bytes,返回 bytes
gzip.decompress(data) 函数 一次性解压 bytes,支持多成员 gzip 数据
gzip.BadGzipFile 异常 无效 gzip 文件引发的异常(3.8 新增),继承自 OSError

gzip.open() 的实现位于 Lib/gzip.py,二进制模式下它等价于 GzipFile(filename, mode, compresslevel, mtime=mtime);文本模式则创建 GzipFile 后用 io.TextIOWrapper 包装。

gzip.open():打开压缩文件的推荐入口

filename 参数

  • 可以是一个实际的文件名字符串(strbytes);
  • 也可以是 os.PathLike 路径对象(3.6 起支持,内部会经过 os.fspath);
  • 还可以是已打开的 file object(3.3 起支持)——例如 io.BytesIO,此时 gzip 数据直接从该对象读写。

mode 参数

mode 支持以下取值(默认 'rb'):

  • 二进制模式:'r''rb''a''ab''w''wb''x''xb''x' 为独占创建,文件已存在则抛 FileExistsError,3.4 起支持);
  • 文本模式:'rt''at''wt''xt'

源码中模式校验逻辑为:若 mode 同时含 't''b',抛出 ValueError;二进制模式下若提供了 encodingerrorsnewline,同样抛出 ValueError(见 Lib/gzip.py),对应测试 test_bad_paramsLib/test/test_gzip.py)。

compresslevel、encoding/errors/newline 与 mtime

  • compresslevel:0~9 的整数,语义与 GzipFile 构造函数一致(1 最快但压缩率最低,9 最慢但压缩率最高,0 表示不压缩);
  • encoding/errors/newline:仅文本模式可用,分别控制 TextIOWrapper 的字符编码、错误处理方式与行结束符处理;
  • mtime:仅关键字参数(keyword-only),Unix 时间戳,会被透传给 GzipFile 构造函数,用于控制写入 gzip 头的 MTIME 字段。

版本演进

  • 3.3:filename 支持 file object;新增文本模式与 encodingerrorsnewline 参数;
  • 3.4:新增 'x''xb''xt' 模式;
  • 3.6:filename 接受 path-like object;
  • 3.15:默认压缩级别由 9 下调为 6——这是大多数压缩工具的默认级别,也是速度与压缩率之间更好的折中;
  • next:新增仅关键字参数 mtime,透传给 GzipFile

源码中默认压缩级别定义为常量 _COMPRESS_LEVEL_TRADEOFF = 6,并与 _COMPRESS_LEVEL_FAST = 1_COMPRESS_LEVEL_BEST = 9 一起构成三种典型档位(Lib/gzip.py),open() 的默认参数即取自该常量。

GzipFile 类深入

构造函数参数语义

GzipFile(filename=None, mode=None, compresslevel=6, fileobj=None, mtime=None)

fileobj 与 filename 二选一(至少其一要给出非平凡值):

  • 新实例基于 fileobj 工作,它可以是普通文件、io.BytesIO,或任何模拟 file 的对象;fileobj=None 时,内部用 builtins.open(filename, mode or 'rb') 打开文件(打开的内部文件对象记录在 myfileobj,close 时会被一并关闭,见 Lib/gzip.py);
  • 当指定了 fileobjfilename 仅用于写入 gzip 头部的 FNAME 字段(原始未压缩文件名)。它默认取 fileobj.name(若可辨认),否则为空字符串,此时头部不含原始文件名;
  • filename 若为 path-like,会经 os.fspath() 规整后保存为公开的 name 属性。

mode:可取 'r'/'rb'/'a'/'ab'/'w'/'wb'/'x'/'xb'。默认取 fileobj.mode(若可辨认),否则为 'rb'。源码还做了两条规范化处理(Lib/gzip.py):传入含 't''U' 的 mode 直接抛 ValueError;传入不含 'b' 的 mode(如 'w')会自动补成 'wb'。注意:

  • 官方文档明确提示:未来版本将不再使用 fileobj 的模式,写入时最好总是显式指定 mode
  • 从 3.9 起,为写入而打开 GzipFile 却未指定 mode 已被标记为弃用(源码在 3.15 快照中仍以 FutureWarning 形式发出警告,Lib/gzip.py)。

compresslevel:0~9 整数。写入时它除了决定 zlib 压缩强度,还会影响 gzip 头部的 XFL 字段:level 9 写 \x02(最大压缩)、level 1 写 \x04(最快压缩)、其余写 \x00(见 Lib/gzip.py 及测试 test_compresslevel_metadataLib/test/test_gzip.py)。

mtime:请求写入 gzip 头的 Unix 时间戳(1970-01-01 00:00:00 UTC 起的秒数):

  • 0 可生成与创建时间无关、可复现的压缩流;
  • 省略或传 None 时使用当前时间;
  • 当系统当前时间落在 1970-01-01 00:00:00 UTC 至 2106-02-07 06:28:15 UTC 之外,或显式传入的 mtime 超出 02**32-1 区间时,实际写入值回退为 0。这一边界在源码 _write_gzip_header() 中以 if not 0 <= mtime < 2**32: mtime = 0 实现(Lib/gzip.py),测试见 test_mtime_out_of_rangeLib/test/test_gzip.py)。

流式与关闭语义

GzipFile 读取时使用 io.BufferedReader,写入时使用 io.BufferedWriter(缓冲大小为 4 * io.DEFAULT_BUFFER_SIZE,见 Lib/gzip.py)。值得注意的关闭行为:

  • 调用 GzipFile.close() 不会关闭底层的 fileobj,这是有意设计——你可能希望在压缩数据之后继续追加内容,也正因如此,可以传入一个以写模式打开的 io.BytesIO 作为 fileobj,压缩结束后用 BytesIO.getvalue() 取回内存缓冲区;
  • 写入模式的 close 会依次:刷新缓冲、写出 compress.flush() 的尾流、再写入 4 字节 CRC32 与 4 字节 ISIZE(未压缩长度对 2**32 取模),见 Lib/gzip.py
  • GzipFile 支持 io.BufferedIOBase 接口,包括迭代与 with 语句,仅 truncate() 未实现;
  • _WriteBufferStream 内部类把缓冲刷新回调转发给 GzipFile,保证 CRC 与长度的统计与数据落盘同步(Lib/gzip.py)。

专有成员:peek、mode、mtime、name

成员 说明 版本
peek(n) 读取 n 个未解压字节但不推进文件位置;返回字节数可能多于或少于请求。注意:它不改变 GzipFile 的位置,却可能改变底层 fileobj 的位置(尤其用 fileobj 构造时) 3.2 新增
mode 属性 读返回 'rb',写返回 'wb'(3.13 之前是整数 1/2) 3.13 变更
mtime 属性 解压时,保存最近一次读取的头部中的 MTIME 时间戳(Unix epoch 秒数的整数);读取任何头部前初始为 None 3.1 新增
name 属性 gzip 文件在磁盘上的路径(strbytes),等价于对原始输入路径调用 os.fspath() 的输出,不做任何额外规范化、解析或展开 3.12 起替代被移除的 filename 属性

mtime 属性的行为有完整测试覆盖:test_mtime 验证写入指定 mtime=123456789 后回读属性得到相同值、读取前属性为 NoneLib/test/test_gzip.py)。

GzipFile 版本历史一览

  • 3.1:支持 with 语句,新增 mtime 构造参数与 mtime 属性;
  • 3.2:支持零填充(zero-padded)文件与不可 seek(unseekable)的文件;
  • 3.3:实现 io.BufferedIOBase.read1()
  • 3.4:支持 'x''xb' 模式;
  • 3.5:支持写入任意 bytes-like object;read() 接受 None 参数;
  • 3.6:接受 path-like object;
  • 3.9:写入时不指定 mode 弃用;
  • 3.12:移除 filename 属性,改用 name
  • 3.15:默认压缩级别由 9 降为 6。

compress() 与 decompress():内存态的一站式压缩/解压

compress(data, compresslevel=6, *, mtime=0)

data 压缩为 gzip 格式的 bytes。与流式接口的关键差异在于 mtime 默认是 0(3.14 起;之前默认当前时间),从而保证输出可复现;若要恢复旧行为(用当前时间),显式传 mtime=None

实现与优化路径(Lib/gzip.py):

  • 3.11 起改为一次性整体压缩而非流式压缩,显著提速:mtime=0 时直接委托 zlib.compress(data, level=..., wbits=31)(wbits=31 自动携带 gzip 头与尾),再重写头部的 MTIME 与 OS 字节;
  • 由于委托 zlib 产生头部,3.11~3.12 期间输出的 OS 字节可能是 zlib 提供的非 255 值;3.13 起保证 OS 字节恒为 255(unknown);
  • mtime 越界(不在 02**32-1)时自动回退为 0。

compresslevelmtime 语义与 GzipFile 构造函数相同。测试 test_compress_mtime_default 验证默认输出可复现(两次 gzip.compress(data) 输出完全一致,Lib/test/test_gzip.py),test_compress_correct_level 则验证不同 compresslevel 的字节级正确性(Lib/test/test_gzip.py)。

decompress(data)

解压 data 并返回未压缩的 bytes该函数能够处理多成员(multi-member)gzip 数据,即多个 gzip 块首尾拼接在一起的文件:decompress() 内部循环读取每个成员的头部、以 wbits=-MAX_WBITS 原始 deflate 解压、逐段校验 CRC32 与 ISIZE,最后拼接返回全部成员的解压结果(Lib/gzip.py)。

性能提示:当数据确定只含单个成员时,直接用 zlib.decompress(data, wbits=31) 更快。3.11 起 decompress() 也改为在内存中一次性解压各成员,取代此前的流式处理。多成员场景的测试覆盖见 test_decompressLib/test/test_gzip.py)。

异常与损坏数据检测

  • BadGzipFile(3.8 新增,继承 OSError):文件头不是 gzip 魔数、压缩方法未知、头部 CRC 不匹配、解压 CRC 校验失败、长度不符等场景均会抛出;
  • 文件在流结束标记前截断时抛 EOFError(如 _read_exactLib/gzip.py 中检测);
  • zlib.error 也可能在底层解压失败时出现。

这些检测逻辑由 _read_gzip_header()Lib/gzip.py)与 _read_eof()Lib/gzip.py)承载:后者读出并比对存储的 CRC32 与 ISIZE(未压缩长度对 2³² 取模),随后还会吞掉 gzip 文件尾部允许存在的零填充字节。对应测试见 test_gzip_BadGzipFile_exceptiontest_bad_gzip_filetest_corrupted_gzip_headertest_read_truncated 等(Lib/test/test_gzip.pyLib/test/test_gzip.py)。

官方使用示例(可复制运行)

读取一个压缩文件:

import gzip
with gzip.open('/home/joe/file.txt.gz', 'rb') as f:
    file_content = f.read()

创建压缩的 GZIP 文件:

import gzip
content = b"Lots of content here"
with gzip.open('/home/joe/file.txt.gz', 'wb') as f:
    f.write(content)

把磁盘上已有的文件整体 GZIP 压缩(流式拷贝,内存占用可控):

import gzip
import shutil
with open('/home/joe/file.txt', 'rb') as f_in:
    with gzip.open('/home/joe/file.txt.gz', 'wb') as f_out:
        shutil.copyfileobj(f_in, f_out)

压缩内存中的二进制字符串:

import gzip
s_in = b"Lots of content here"
s_out = gzip.compress(s_in)

文本模式的实战补充

按文档约定,读取文本类压缩内容时应使用 gzip.open 的文本模式,或手动用 io.TextIOWrapper 包装 GzipFile。例如按 UTF-8 读、写压缩文本,并显式处理换行:

import gzip

# 文本写入(自动编码)
with gzip.open('/home/joe/log.txt.gz', 'wt', encoding='utf-8') as f:
    f.write('line one\nline two\n')

# 文本读取(自动解码,支持通用换行)
with gzip.open('/home/joe/log.txt.gz', 'rt', encoding='utf-8', newline=None) as f:
    for line in f:
        print(line, end='')

注意文本模式与二进制模式的差异:文本模式下写入 str、读出 str,且 encoding/errors/newline 参数生效;二进制模式下这些参数必须省略(传入即抛 ValueError)。测试 test_text_modestest_encodingtest_encoding_error_handlertest_newline 完整覆盖了上述行为(Lib/test/test_gzip.py)。

在内存中读写(BytesIO + GzipFile)

由于 GzipFile.close() 不会关闭传入的 fileobj,用 io.BytesIO 即可把压缩数据留在内存中:

import gzip, io

# 压缩到内存
buf = io.BytesIO()
with gzip.GzipFile(fileobj=buf, mode='wb', mtime=0) as gz:
    gz.write(b'some payload')
compressed = buf.getvalue()

# 从内存解压
with gzip.GzipFile(fileobj=io.BytesIO(compressed), mode='rb') as gz:
    print(gz.read())

这种模式常用于网络传输前的就地压缩,也是 Lib/test/test_gzip.py 中大量用例验证的核心场景(见 TestGzip.test_write_read_with_pathlike_file 等)。open() 同样接受 file object 作为第一参数,例如 gzip.open(io.BytesIO(compressed), 'rt', encoding='utf-8')(测试见 test_fileobjLib/test/test_gzip.py)。

命令行接口:python -m gzip

gzip 模块自带简单 CLI,用于压缩/解压文件。执行后 输入文件会被保留(这与 GNU gzip 删除输入文件的行为不同)。入口为 main()Lib/gzip.py),模块 docstring 将其描述为"像 gzip 一样工作,但不删除输入文件"。

调用方式:

python -m gzip [--fast | --best] [file ...]
python -m gzip -d | --decompress [file ...]
python -m gzip -h | --help

命令行选项

选项 说明
file 待处理的文件;若未指定文件,则从 sys.stdin 读取数据(CLI 中用 - 表示 stdin)
--fast 使用最快的压缩方法(压缩率最低),即压缩级别 1
--best 使用最慢的压缩方法(压缩率最高),即压缩级别 9
-d, --decompress 解压给定文件,行为类似 gunzip
-h, --help 显示帮助信息

默认压缩级别为 6(3.8 新增该 CLI 时即为默认)。--fast--best-d 三者互斥,由 argparseadd_mutually_exclusive_group 保证;同时传入会直接报错退出,测试见 test_compress_fast_best_are_exclusivetest_decompress_cannot_have_flags_compressionLib/test/test_gzip.py)。

CLI 行为细节

  • 压缩文件:为输入 foo 生成 foo.gz
  • 解压文件:要求输入文件名以 .gz 结尾,否则输出错误 filename doesn't end in .gz: 'xxx' 并以退出码 1 结束(Lib/gzip.py,测试见 Lib/test/test_gzip.py),解压结果写入去掉 .gz 后缀的同名文件;
  • 标准输入/输出:不指定文件(或使用 -)时压缩读 stdin 写 stdout;-d 配合 stdin 时从 stdin 解压到 stdout;
  • 压缩流块大小为 READ_BUFFER_SIZE = 128 * 1024Lib/gzip.py)。

命令行行为由 TestCommandLine 类系统验证,覆盖 stdin/stdout 往返、文件到文件、默认输出名、--fast/--best 互斥等(Lib/test/test_gzip.py)。

从源码看 gzip 文件格式的落盘细节

GzipFile 写入时按 RFC 1952 构造文件头,_write_gzip_header()Lib/gzip.py)依次写入:

  1. 魔数 \x1f\x8b\037\213)与压缩方法 \x08(deflate);
  2. FLG 标志字节:仅当可写入文件名时置 FNAME 位(原始文件名按 RFC 1952 要求为 Latin-1 编码,无法表示的文件名会被静默跳过;文件名若以 .gz 结尾会去掉该后缀再写入头部);
  3. MTIME:4 字节小端时间戳(越界时回退 0,见上文 mtime 规则);
  4. XFL:9→\x02、1→\x04、其他→\x00
  5. OS 字节:恒为 \xff(255,unknown);
  6. 可选 FNAME:以 \x00 结尾的原始文件名。

测试 test_metadata 逐字节断言了头部魔数、CM=8、FLG、小端 MTIME、XFL 与 OS 字节 \xff,并核对了尾部 CRC32 与 ISIZE(Lib/test/test_gzip.py)。

读取端 _read_gzip_header() 则会解析并校验上述各字段:魔数不符抛 BadGzipFile('Not a gzipped file')、压缩方法非 8 抛 BadGzipFile('Unknown compression method');对 FLG 无标志(gzip.compresszlib.compress 的产物)或仅 FNAME 的常见情况做提前返回优化,其余复杂标志(FEXTRA/FCOMMENT/FHCRC)则完整解析并做头部 CRC16 校验。

相关主题与进一步阅读

  • 数据压缩基础层:gzip 格式的底层 deflate 压缩由 zlib 模块完成,相关文档见 Doc/library/zlib.rstzlib.compress/zlib.decompress 配合 wbits=31 即可生成/解析单成员 gzip 流;
  • 同族压缩模块bz2lzma 模块与本模块共享底层流基础设施(compression._common._streams),如果追求更高压缩率可参考它们的文档(见 Lib/compression/ 目录);
  • 压缩成为瓶颈时:标准库文档建议关注采用 Intel ISA-L 加速的 python-isal 兼容包(API 与 gzip 基本一致,可作性能替换方案),可依据实际场景自行评估,本仓库源码与测试并不涉及该第三方实现;
  • 参考实现Lib/gzip.py(完整模块实现,含头部读写、CRC 校验与 CLI)、Lib/test/test_gzip.py(覆盖 API 行为、文本模式、字节级元数据、CLI 等约数十个测试用例)。

本文所描述的默认压缩级别 6、mtime 默认 0、GzipFile 相关弃用与变更,均以当前仓库(对应文档标注的 3.15 及更新版本行为)为准;如果读者运行的是更早的 Python 版本,请以对应版本的官方文档与实际行为为准。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.13 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
529
593
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
915
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.35 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
515
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388