You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python下载大文件时是否支持保存MD5状态实现哈希断点续算?

问题解答

你现有代码存在几处笔误:变量名hd和HD大小写不一致、迭代方法应为iter_content而非iter_contents、chunk_size需要传入整数类型(256KB对应1024 * 256)。

你需要的断点续传同步计算哈希的需求是可行的,目前有两种主流实现方案,具体如下:

方案1:基于本地已下载文件重建哈希状态(兼容性最优,无额外依赖)

该方案不需要额外保存哈希计算的中间状态,利用你断点续传原本就需要存储的「已下载字节数」即可实现,适合所有Python版本。
实现逻辑:

  • 你实现断点续传时必然会持久化存储当前已完成下载的字节偏移量(记为downloaded_bytes),下次启动先读取这个值
  • 续传初始化哈希对象时,先按块读取本地已下载的部分文件,逐个块调用md5.update(),完成后即可得到和中断前完全一致的哈希计算状态
  • 之后再发送带Range: bytes=downloaded_bytes-的请求下载剩余内容,新下载的块继续同步写入文件和更新哈希对象即可

示例代码:

import os
import requests
import hashlib

# 持久化存储下载进度的文件
META_FILE = "download.meta"
TARGET_FILE = "Out.File"
CHUNK_SIZE = 1024 * 256  # 256KB

# 读取已下载进度
if os.path.exists(META_FILE):
    with open(META_FILE, "r") as f:
        downloaded_bytes = int(f.read().strip())
else:
    downloaded_bytes = 0

# 初始化哈希对象,重建之前的计算状态
md5 = hashlib.md5()
if downloaded_bytes > 0:
    with open(TARGET_FILE, "rb") as f:
        while downloaded_bytes > 0:
            chunk = f.read(min(CHUNK_SIZE, downloaded_bytes))
            if not chunk:
                break
            md5.update(chunk)
            downloaded_bytes -= len(chunk)
    # 重置为当前实际已下载的偏移量
    downloaded_bytes = os.path.getsize(TARGET_FILE)

# 发起断点续传请求
headers = {"Range": f"bytes={downloaded_bytes}-"}
resp = requests.get("你的下载URL", headers=headers, stream=True)
resp.raise_for_status()

# 续传下载逻辑
with open(TARGET_FILE, "ab") as f:
    for chunk in resp.iter_content(chunk_size=CHUNK_SIZE):
        if not chunk:
            break
        f.write(chunk)
        md5.update(chunk)
        downloaded_bytes += len(chunk)
        # 定期更新进度到元数据文件,可根据需求调整频率
        with open(META_FILE, "w") as meta_f:
            meta_f.write(str(downloaded_bytes))

# 下载完成后校验哈希
final_md5 = md5.hexdigest()
print(f"最终MD5值: {final_md5}")
# 清理临时元数据文件
os.remove(META_FILE)

方案2:直接序列化哈希对象(性能最优,无需重读已下载内容)

Python 3.8及以上版本中,hashlib的哈希对象原生支持pickle序列化,你可以直接将计算到一半的哈希对象和下载进度一起持久化存储,续传时直接加载即可,不需要重新读取已下载的大文件。
实现逻辑:

  • 每次更新下载进度的同时,将当前的哈希对象用pickle序列化后和进度一起存储到本地
  • 续传时直接反序列化得到之前的哈希对象,直接继续计算新下载块的哈希即可

示例代码:

import os
import pickle
import requests
import hashlib

META_FILE = "download.meta"
TARGET_FILE = "Out.File"
CHUNK_SIZE = 1024 * 256

md5 = hashlib.md5()
downloaded_bytes = 0

# 加载之前的进度和哈希状态
if os.path.exists(META_FILE):
    with open(META_FILE, "rb") as f:
        meta = pickle.load(f)
        downloaded_bytes = meta["downloaded_bytes"]
        md5 = meta["md5_obj"]

# 断点续传请求逻辑同上
headers = {"Range": f"bytes={downloaded_bytes}-"}
resp = requests.get("你的下载URL", headers=headers, stream=True)
resp.raise_for_status()

with open(TARGET_FILE, "ab") as f:
    for chunk in resp.iter_content(chunk_size=CHUNK_SIZE):
        if not chunk:
            break
        f.write(chunk)
        md5.update(chunk)
        downloaded_bytes += len(chunk)
        # 定期持久化进度和哈希状态
        with open(META_FILE, "wb") as meta_f:
            pickle.dump({
                "downloaded_bytes": downloaded_bytes,
                "md5_obj": md5
            }, meta_f)

final_md5 = md5.hexdigest()
print(f"最终MD5值: {final_md5}")
os.remove(META_FILE)

注意事项

  • 方案2依赖Python 3.8+的pickle支持,且pickle文件存在反序列化安全风险,不要加载来源不明的元数据文件
  • 如果你需要跨Python版本/跨设备恢复下载,优先选择方案1,兼容性更强
  • 两种方案都支持SHA256等其他哈希算法,仅需将hashlib.md5()替换为对应算法即可

内容的提问来源于stack exchange,提问作者TLaczy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 14:54:01