Python hashlib.file_digest 怎样直接计算文件摘要
来源:17golang原创
时间:2026-11-13 18:29:38 300浏览 收藏
如果目标是从一个已经打开的二进制文件直接得到 SHA-256、SHA-512 等摘要,Python 3.11 及以上可以使用 hashlib.file_digest()。它把“读取文件、持续更新哈希对象、返回最终摘要”这段固定样板收拢成一次调用:
import hashlib
def file_sha256(path):
# 以二进制、阻塞模式打开文件,file_digest 会消费其中的内容。
with open(path, "rb") as source:
digest = hashlib.file_digest(source, "sha256")
# hexdigest 适合写入清单、日志或与另一份十六进制摘要比较。
return digest.hexdigest()
官方地址:https://docs.python.org/3/library/hashlib.html#hashlib.file_digest
这篇只讨论文件对象、摘要算法、文件位置和迁移边界,不把文件摘要当成密码存储方案,也不展开大文件分片协议。
file_digest 解决的是哪一段重复代码
旧代码通常先创建哈希对象,再循环读取固定大小的字节块,最后调用 hexdigest()。这种写法没有错,但每个项目都要重复处理块大小、循环结束和资源关闭。file_digest(fileobj, digest) 直接接收一个可读的二进制文件对象,并返回已经更新完成的摘要对象。
第二个参数可以是算法名称字符串、哈希构造器,或返回哈希对象的可调用对象。得到的仍然是标准 hashlib 哈希对象,因此可以继续使用 digest()、hexdigest() 和 name 等接口。它不是把结果直接返回成字符串,格式化动作仍由调用方决定。

用算法名称直接计算 SHA-256
最常见的场景是把算法名作为字符串传入。文件必须用 rb 打开,因为摘要计算针对的是原始字节;如果用文本模式读取,换行转换或编码处理就可能让摘要与原文件不一致。
from pathlib import Path
import hashlib
def digest_file(path: str, algorithm: str = "sha256") -> str:
# 先保留路径语义,打开动作放在 with 内,确保异常时也能关闭句柄。
file_path = Path(path)
with file_path.open("rb") as source:
digest = hashlib.file_digest(source, algorithm)
# 返回稳定的十六进制文本,不把摘要对象泄漏到资源管理范围之外。
return digest.hexdigest()
sha256_text = digest_file("release.tar.gz")
print(sha256_text)
算法名称写错或当前构建不可用时,异常会在调用处暴露。不要为了“兼容”而静默改成另一个算法,否则清单和校验端会得到不同语义。发布文件校验一般会约定算法名与十六进制大小写,保存摘要前先确定这两个约定。
文件位置和关闭责任不能忽略
file_digest 会消费文件对象的内容。官方文档还特别提醒:函数可能绕过 Python 层 I/O,直接使用 fileno(),调用成功或抛出异常后,文件对象都应视为处于未知状态。因此最稳妥的边界是为一次摘要创建一个新打开的文件对象,并让 with 负责关闭。
import hashlib
def digest_from_existing(source) -> str:
# 调用方若复用文件对象,必须先明确自己要摘要的字节范围。
source.seek(0)
digest = hashlib.file_digest(source, "sha256")
# file_digest 返回后不再依赖 source 的当前位置,调用方仍要负责关闭它。
return digest.hexdigest()
这个示例表达的是边界,不是说所有文件对象都支持 seek(0)。如果对象来自网络流、管道或某些 socket 包装,它可能只能向前读取;这时应在接口层决定是否允许一次性消费,不能假设摘要函数会自动回退到开头。
文件还应以阻塞模式打开。Python 3.14 起,非阻塞文件会抛出 BlockingIOError;迁移旧代码时如果摘要接口突然在特定文件描述符上失败,先检查打开模式和上游 I/O 封装,而不是重试同一个非阻塞对象。

需要 HMAC 时传入可调用的摘要工厂
如果任务不是单纯计算公开文件指纹,而是要把文件内容纳入 HMAC,可以传入返回哈希对象的可调用对象。官方示例使用一个已经创建的 HMAC 对象,并通过 lambda 把它交给 file_digest:
import hashlib
import hmac
def file_hmac(path: str, secret: bytes) -> str:
# HMAC 对象负责密钥语义,file_digest 只负责把文件字节送入它。
mac = hmac.HMAC(secret, digestmod=hashlib.sha256)
with open(path, "rb") as source:
digest = hashlib.file_digest(source, lambda: mac)
# 返回 HMAC 的十六进制结果;密钥不要写入日志或文章示例的真实配置。
return digest.hexdigest()
这里的 lambda: mac 返回同一个 HMAC 对象,因此调用完成后 digest 与 mac 指向同一个结果对象。实际业务中应把密钥放在受控的密钥配置中,文件摘要和 HMAC 的用途、密钥管理与校验协议也要分开描述。
从手写循环迁移时检查这五项
| 检查项 | 迁移前后要保持的语义 |
|---|---|
| 输入模式 | 保持二进制读取,不能把文本解码后的字符重新编码来代替原始字节。 |
| 算法名称 | 明确使用 sha256、sha512 或约定的构造器,不因异常静默替换算法。 |
| 文件位置 | 确认对象从哪里开始读;复用对象时不要把上一次读取留下的位置当成默认起点。 |
| 阻塞属性 | 文件对象应处于阻塞模式,非阻塞对象在新版本中可能抛出 BlockingIOError。 |
| 资源生命周期 | file_digest 不替调用方关闭文件;优先用 with 管理 open 返回的对象。 |
如果只是校验发布包,最小迁移通常就是“保留算法约定、把读取循环替换为 file_digest、继续用 hexdigest 输出”。如果目标是密码存储、抗篡改签名或密钥派生,应该选择对应的密码学接口,不要仅因为摘要 API 方便就把普通哈希直接当作安全方案。
常见问题
file_digest 从 Python 哪个版本开始提供?
官方文档标注它在 Python 3.11 加入。需要支持更老版本时,保留手写的 read() 与 update() 循环,或在项目兼容层中做明确分支。
调用 file_digest 后还能继续读取同一个文件对象吗?
不要依赖它调用后的文件位置或内部状态。文档要求把对象状态视为未知;如果后续还要读取,重新打开文件或在接口边界重新建立明确的读取策略。
为什么一定要用 rb 而不是 r?
摘要针对字节序列。文本模式会引入解码和平台换行语义,可能让参与摘要的内容不再等于磁盘上的原始字节。
file_digest 能代替密码哈希吗?
不能直接这样理解。它是文件或文件类对象的摘要便捷接口;密码存储需要带盐、可调成本和专门的密钥派生方案。
一句话记忆:为一次摘要准备一个二进制、阻塞的文件对象,用明确的算法调用 hashlib.file_digest,结果由调用方格式化,文件仍由调用方关闭。 -
369 收藏
-
344 收藏
-
464 收藏
-
327 收藏
-
349 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习