python实现文件断点续传的关键在于利用http协议的range请求头,通过1.检查本地文件大小确定下载起点;2.在请求头中添加range字段如bytes=1024-以请求指定字节范围;3.发送请求后根据状态码判断服务器支持情况,206表示支持断点续传,200则需重新下载;4.解析content-range响应头获取文件总大小并校验续传一致性;5.以追加模式写入数据并实时更新进度;6.结合head请求预判服务器是否支持accept-ranges: bytes及content-length;7.加入异常处理、重试机制与网络中断恢复策略;8.通过etag或last-modified配合if-range防止服务器文件变更导致的下载错乱;9.确保流式下载stream=true和分块读取iter_content以节省内存;10.最终完成下载后建议进行文件完整性校验,整个过程需兼顾服务器兼容性与系统健壮性,从而实现高效可靠的断点续传功能。

Python实现文件断点续传,主要依赖于HTTP协议的
Range
要实现断点续传,我们首先得理解HTTP的几个关键点。最核心的就是
Range
Range: bytes=1024-
206 Partial Content
Content-Range
200 OK
Range
具体来说,实现这个功能,我们需要:
立即学习“Python免费学习笔记(深入)”;
requests
Range
headers={'Range': f'bytes={已下载大小}-'}206 Partial Content
200 OK
Range
404 Not Found
500 Internal Server Error
说实话,我最初接触这个的时候,觉得概念挺简单,不就是加个头嘛。但实际写起来,你会发现各种边缘情况和服务器行为差异才是真正的挑战。
这是个很实际的问题,毕竟不是所有服务器都那么“友好”。最直接的办法是发送一个
HEAD
HEAD
GET
发送
HEAD
Accept-Ranges
Accept-Ranges: bytes
Range
none
Content-Length
Range
我个人经验是,光看
Accept-Ranges
Range
Range: bytes=0-0
206 Partial Content
200 OK
Range
使用
requests
import requests
import os
import time
def download_file_resumable(url, local_filename, chunk_size=8192):
"""
实现文件的断点续传下载
"""
if os.path.exists(local_filename):
# 检查本地文件大小,作为续传的起点
downloaded_size = os.path.getsize(local_filename)
mode = 'ab' # 追加模式
headers = {'Range': f'bytes={downloaded_size}-'}
print(f"检测到本地文件 {local_filename},大小 {downloaded_size} 字节,尝试从此处续传。")
else:
downloaded_size = 0
mode = 'wb' # 写入模式
headers = {}
print(f"本地无文件 {local_filename},将从头开始下载。")
try:
# 第一次请求,检查服务器是否支持Range
# 实际下载时,可以先发HEAD请求判断,这里直接用GET并处理200/206
with requests.get(url, headers=headers, stream=True, timeout=30) as r:
# 检查服务器是否支持断点续传,以及响应状态码
if r.status_code == 206:
print("服务器支持断点续传 (206 Partial Content)。")
# 确保Content-Range头存在且格式正确
content_range = r.headers.get('Content-Range')
if content_range:
# Content-Range: bytes 0-1023/10240
total_size_str = content_range.split('/')[-1]
try:
total_size = int(total_size_str)
except ValueError:
print("警告: 无法解析Content-Range中的总大小。")
total_size = None
else:
print("警告: 206响应中缺少Content-Range头部。")
total_size = None # 无法确定总大小,可能需要重新下载
# 如果本地文件大小与服务器响应的起始字节不符,可能需要重新下载
if total_size is not None and downloaded_size > 0 and downloaded_size != int(content_range.split(' ')[1].split('-')[0]):
print("警告: 本地文件大小与服务器续传起始点不符,可能需要重新下载。")
# 这里可以加入逻辑,比如删除本地文件,重新下载
# os.remove(local_filename)
# return download_file_resumable(url, local_filename) # 重新调用
# 为了简化,这里选择继续,但用户需注意
pass
elif r.status_code == 200:
print("服务器不支持断点续传或忽略了Range请求 (200 OK),将重新下载整个文件。")
# 如果是200,说明服务器发了整个文件,需要从头开始写入
mode = 'wb'
downloaded_size = 0
total_size = int(r.headers.get('Content-Length', 0))
else:
print(f"下载失败: 服务器返回状态码 {r.status_code}")
return False
# 获取文件总大小,用于进度显示
if total_size is None:
# 尝试从Content-Length获取,如果206没有Content-Range
total_size = int(r.headers.get('Content-Length', 0)) + downloaded_size # 对于206,Content-Length是剩余部分的大小
# 写入文件
with open(local_filename, mode) as f:
for chunk in r.iter_content(chunk_size=chunk_size):
if chunk: # 过滤掉保持连接的空数据块
f.write(chunk)
downloaded_size += len(chunk)
# 简单的进度显示
if total_size:
progress = (downloaded_size / total_size) * 100
print(f"\r下载进度: {progress:.2f}% ({downloaded_size}/{total_size} 字节)", end='')
else:
print(f"\r已下载: {downloaded_size} 字节", end='')
print(f"\n文件下载完成: {local_filename}")
return True
except requests.exceptions.RequestException as e:
print(f"网络请求错误: {e}")
return False
except Exception as e:
print(f"发生未知错误: {e}")
return False
# 示例使用
if __name__ == "__main__":
# 找一个支持断点续传的URL,比如一些大型文件下载地址
# 注意:请替换为实际可用的URL
test_url = "http://speedtest.tele2.net/1MB.zip" # 示例,可能会失效
# test_url = "https://example.com/some_large_file.zip" # 替换为你的文件URL
output_file = "downloaded_file.zip"
print(f"尝试下载: {test_url} 到 {output_file}")
success = download_file_resumable(test_url, output_file)
if success:
print("下载任务成功完成。")
else:
print("下载任务失败。")
# 模拟中断后再次运行,看是否能续传
# 可以手动中断程序后再次运行,或者在函数内部模拟中断(比如下载一部分后raise Exception)
# print("\n模拟中断后再次尝试下载...")
# time.sleep(2) # 模拟中断
# success_resume = download_file_resumable(test_url, output_file)
# if success_resume:
# print("续传任务成功完成。")
# else:
# print("续传任务失败。")这段代码里,我尝试把可能遇到的状态都考虑进去。
stream=True
requests
iter_content
Content-Range
206
Content-Length
说实话,断点续传听起来美好,但实际应用中总会碰到一些“坑”,这就像你以为代码写完了,结果测试一跑,各种意想不到的边界条件就冒出来了。
Range
HEAD
GET
requests
Retry
Content-Length
ETag
Last-Modified
If-Range
ETag
Last-Modified
206
200
threading.Lock
fcntl
Content-Length
处理这些挑战,就像在修补一个漏水的桶,你得找到所有的洞,并用合适的材料堵上。这不仅仅是技术问题,更是一种对系统健壮性和用户体验的思考。
以上就是Python怎样实现文件断点续传?HTTP请求控制的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号