当前位置:首页 > 文章列表 > 文章 > python教程 > Python compression.zstd 怎样读取大压缩流

Python compression.zstd 怎样读取大压缩流

来源:17golang原创 2026-10-14 13:57:01 0浏览 收藏

读取几十 GB 的 .zst 文件时,最容易踩的坑是直接调用 zstd.decompress():它会把解压结果作为一个完整的 bytes 返回,文件越大,瞬时内存压力越明显。Python 3.14 新增的 compression.zstd 提供了文件型接口和增量解压器,更适合按块处理大压缩流。

官方文档:https://docs.python.org/3.14/library/compression.zstd.html

本文只解决一个问题:怎样让解压结果以固定大小的块进入业务处理。文件场景优先用 zstd.open();输入来自管道、socket 或其他类文件对象时,再使用 ZstdDecompressor 的增量接口。

compression.zstd 适合解决什么问题

compression.zstd 在 Python 3.14 加入,模块提供 open()、ZstdFile、一次性 compress/decompress,以及增量的 ZstdCompressor 和 ZstdDecompressor。其中,zstd.open() 返回的对象支持缓冲二进制文件接口,可以像普通文件一样读取;这正好把“解压”和“消费数据”拆成一块一块的动作。

如果目标只是处理一个小字节串,一次性函数很直接;如果目标是大文件,应该让每次读取的大小成为明确的内存预算。例如把块大小设为 1 MiB,业务层就只需要为当前处理块、少量缓冲和自己的临时对象预留空间,不必按完整解压尺寸估算。

用 zstd.open 按块读取大文件

对磁盘上的 .zst 文件,先使用二进制读取模式打开,再循环调用 read(CHUNK_SIZE)。循环体里直接解析、写出或统计当前块,处理完成后让引用离开当前迭代。

.zst 文件通过 zstd.open 和 ZstdFile 按固定块交给处理逻辑的静态结构说明图

图1:文件型 Zstandard 流从压缩输入到处理块的原创静态结构说明图,不是终端或运行截图。

from compression import zstd

CHUNK_SIZE = 1024 * 1024  # 每次只把约 1 MiB 的解压数据交给业务层。


def consume_zstd_file(path: str, output_path: str) -> int:
    total = 0
    with zstd.open(path, "rb") as source, open(output_path, "wb") as target:
        while True:
            chunk = source.read(CHUNK_SIZE)
            if not chunk:
                break  # 空字节表示已经读到解压后的文件末尾。
            target.write(chunk)  # 实际项目可在这里解析,而不是再次完整缓存。
            total += len(chunk)
    return total


written = consume_zstd_file("events.zst", "events.ndjson")
print(f"写出解压数据:{written} 字节")

这里的 target.write(chunk) 只是一个最小的消费例子。如果处理的是 NDJSON,不要为了方便把所有块拼接成一个大字符串;可以在块之间保留一小段未完成的行,找到换行符后立即交给 JSON 解析器。

非文件输入用增量解压器

当压缩数据来自网络读取、管道或自定义的分块来源时,可以给 ZstdDecompressor.decompress() 传入输入块,并用 max_length 限制一次返回的解压数据量。它与文件接口的区别是:你需要自己管理输入块、输出块和当前帧状态。

输入块经过 ZstdDecompressor 和 max_length 形成输出块并暴露 eof needs_input unused_data 状态的静态结构说明图

图2:增量解压器与帧边界状态的原创静态关系说明图,不是运行结果截图。

from compression import zstd

OUTPUT_LIMIT = 1024 * 1024  # 限制单次交给业务层的解压输出大小。


def consume_stream(chunks):
    decoder = zstd.ZstdDecompressor()
    for compressed_chunk in chunks:
        pending = compressed_chunk
        while pending or not decoder.needs_input:
            output = decoder.decompress(pending, max_length=OUTPUT_LIMIT)
            pending = b""  # 解压器可能已经把输入缓冲在内部。
            if output:
                yield output  # 调用方应立即处理,不要把所有块收集到列表。
            if decoder.eof:
                break  # 当前帧结束;后续数据是否属于下一帧要另行决定。
        if decoder.eof:
            break


for data_block in consume_stream(read_from_socket()):
    handle(data_block)  # 业务层按块消费网络解压结果。

max_length 到达上限时,needs_input 可能仍为 False,表示解压器内部还有输出可取;因此示例会在不提供新输入的情况下继续调用一次。相反,needs_input 为 True 时,才需要等待下一块压缩输入。

多帧、EOF 和模块缺失要单独处理

文件接口和模块级 decompress() 可以处理拼接的多个压缩帧,但 ZstdDecompressor 不会自动透明地处理多帧输入。使用增量接口时,读到 eof 后不要把剩余字节悄悄当作同一帧;如果协议允许连续帧,应根据帧边界重新创建解压器,并把剩余输入交给下一帧。

unused_data 用来查看当前帧结束后的剩余数据,eof 用来判断结束标记是否已到达,needs_input 用来判断是否还需要更多压缩输入。发生格式损坏或解压初始化失败时捕获 zstd.ZstdError,记录输入来源并停止消费,不要继续把不完整输出写入下游。

from compression import zstd


def decode_one_frame(data: bytes) -> bytes:
    decoder = zstd.ZstdDecompressor()
    try:
        result = decoder.decompress(data)
    except zstd.ZstdError as exc:
        # 格式错误时停止输出,避免下游误把半截数据当成完整结果。
        raise ValueError("Zstandard 数据不可解压") from exc
    if not decoder.eof:
        raise ValueError("输入尚未包含完整的 Zstandard 帧")
    if decoder.unused_data:
        # 当前函数只处理一帧;多帧协议应把这段数据交给新的解压器。
        raise ValueError("输入包含当前函数未处理的后续帧")
    return result

另外,compression.zstd 是可选模块。如果目标 Python 是 3.14 或更高版本但导入仍失败,要先确认发行版是否构建了这个可选模块;不能仅凭 Python 主版本号就假定它一定存在。生产代码可以在启动阶段给出清楚的依赖提示,而不是等到收到第一份压缩数据时才暴露错误。

把块大小当成接口边界

文件型读取和增量解压都能控制“单次输出”,但它们不会替业务层控制更深一层的内存:解析器可能保留半条记录,解压后的单块也可能触发临时对象分配。因此建议把块大小、未完成记录缓存和下游写入策略放在同一处设计。

场景优先接口关键边界
本地单个 .zst 文件zstd.open()read(CHUNK_SIZE) 后立即处理
socket、管道或自定义输入ZstdDecompressormax_length、needs_input、eof
可能拼接多个帧zstd.open() 或逐帧管理解压器识别 unused_data,不要静默丢弃

常见问题

为什么不用 zstd.decompress()?它适合小输入或确实需要完整结果的场景;大流量处理应改用文件接口或增量解压器。

块大小越小越省内存吗?通常会降低单块内存,但调用次数和系统开销会增加。先用 256 KiB 到 1 MiB 这类明确预算,再结合下游处理速度调整。

只拿到半块压缩数据会失败吗?不一定。增量解压器可以等待更多输入;关键是根据 needs_input 决定是否继续读取,而不是把一次 decompress() 返回空字节误判成结束。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Python 3.15 t-string 怎样用于模板化文本Python 3.15 t-string 怎样用于模板化文本
上一篇
Python 3.15 t-string 怎样用于模板化文本
Python Fraction 近似浮点数时怎样控制最大分母
下一篇
Python Fraction 近似浮点数时怎样控制最大分母
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    471次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    530次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    549次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    499次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    317次使用