Python 断点续传的实现思路

3次阅读

断点续传核心是准确记录并恢复文件偏移量,依赖临时文件或目标文件大小获取已下载字节数,http需Range头与206响应,本地传输靠seek()定位,写入须用追加模式并强制fsync,完成后须校验哈希且原子替换文件。

Python 断点续传的实现思路

断点续传的核心是记录和恢复文件偏移量

关键不在“断”,而在“续”——必须让程序知道上次传到哪了。常见做法是用一个临时文件(如 filename.part)保存已写入的字节数,或直接读取目标文件当前大小作为续传起点。HTTP 协议靠 Range 请求头实现服务端分片,而本地文件传输则依赖 seek() 定位写入位置。

requests + Range 头实现 HTTP 断点续传

服务端需支持 Accept-Ranges: bytes,否则 Range 请求会返回 200 而非 206。实操时先检查目标文件是否存在,再用 os.path.getsize() 获取已下载字节数,构造请求头:

headers = {"Range": f"bytes={downloaded_size}-"}

注意:Range 值末尾带短横线表示“从该位置到结尾”,不要写成 f"bytes={downloaded_size}-{total_size-1}"(你未必知道 total_size)。

  • 收到 206 响应才可续传;若返回 200,说明服务端不支持,得重下
  • 写入文件前必须用 open(..., "ab") 模式,不能用 "wb" 覆盖
  • 务必校验 Content-Range 响应头中的起始偏移是否匹配预期

本地文件复制的断点续传更简单但易错

本质是 seek() + read() + write() 的组合。难点在于:源文件可能被修改、目标路径权限不足、磁盘空间突然不足。建议步骤:

立即学习Python免费学习笔记(深入)”;

  • os.stat(src).st_size 获取源文件总大小
  • os.path.getsize(dst) 获取目标已写大小,确认未超源大小
  • 打开目标文件用 "r+b" 模式,fp.seek(downloaded_size) 定位
  • 循环 read(8192) 写入,每次写完立即 fp.flush()os.fsync(fp.fileno())

漏掉 fsync 可能导致断电后最后几 KB 丢失,且不会报错。

别忽略校验和与原子性

断点续传完成后,md5sha256 校验不是可选项。更关键的是:不要直接覆盖原文件。正确流程是下载到 file.tmp → 校验通过 → os.replace("file.tmp", "file")windows 下 replace 是原子操作,linux 下也等效于 rename。用 shutil.move 或直接 os.rename 在某些 NFS 或容器挂载场景会失败。

真正麻烦的从来不是“怎么续”,而是“续完怎么信”。校验失败时,是删掉部分文件重来,还是尝试修复?这取决于业务容忍度,但代码里必须有明确分支处理,不能只打印一句“校验失败”。

text=ZqhQzanResources