ftplib本身不支持断点续传,需手动实现:用retrbinary()回调记录字节数,通过sendcmd("REST offset")告知服务器续传位置,并以临时文件、追加写入、落盘偏移、新建连接、指数退避重试等保障可靠性。

ftplib 本身不支持断点续传,必须手动实现;核心是用 FTP.retrbinary() 的回调函数记录已接收字节数,并在下次连接时用 FTP.sendcmd("REST " + str(offset)) 告诉服务器从哪继续。
为什么 ftplib 没有现成的 resume 参数?
因为 FTP 协议层面虽支持 REST 命令,但 ftplib 把底层控制权留给了用户——它只提供原始命令接口,不封装业务逻辑。这意味着你得自己管理偏移量、处理连接中断后的重试、校验文件完整性。
常见错误现象:error_perm: 501 REST not supported(服务器禁用了该命令),或 error_reply: 425 Can't open data connection(被动模式未正确设置)。
实操建议:
- 先用
FTP.sendcmd("HELP")确认服务器是否返回REST在支持列表中 - 始终在调用
retrbinary()前显式启用被动模式:ftp.set_pasv(True) - 不要依赖
FTP.size()获取文件大小——某些服务器返回 -1 或抛异常,应提前通过FTP.sendcmd("SIZE filename")并捕获异常来兜底
如何安全地记录和恢复下载偏移量?
本地偏移量不能只存在内存里,必须落盘;但直接写入目标文件再中断,会导致文件末尾残留脏数据。正确做法是:先下载到临时文件(如 file.zip.part),完成后再重命名为目标名。
实操建议:
- 用
os.path.getsize()获取已下载临时文件大小作为初始 offset,而不是靠文件名后缀或时间戳推断 - 写入临时文件时用
"ab"模式(追加二进制),避免覆盖已有内容 - 每次成功写入后,立即调用
file.flush()和os.fsync(file.fileno()),防止系统缓存导致偏移量与实际磁盘不一致 - 恢复前检查临时文件是否完整:对比本地已下大小与服务器总大小,若相等就直接跳过下载
如何处理连接中断并自动重试?
网络抖动或服务器超时会触发 ftplib.error_temp、OSError 或 socket.timeout。ftplib 不自动重连,你需要在外层捕获异常、关闭旧连接、重建 FTP 实例、重新登录、再发 REST 命令。
实操建议:
- 不要复用同一个
FTP实例跨多次下载尝试——连接状态不可靠,每次都应新建实例并调用login() -
REST命令必须紧跟在login()之后、retrbinary()之前发送,且只能对当前要下载的文件生效 - 重试次数建议设为 3–5 次,每次间隔用
time.sleep(2 ** attempt)指数退避,避免雪崩请求 - 若重试后仍失败,检查是否因服务器限制了同一 IP 的并发连接数,可加
ftp.set_debuglevel(1)查看底层交互日志
最易被忽略的是:有些 FTP 服务器(尤其是 Windows IIS FTP)在 REST 后要求紧接着使用相同的数据连接模式(主动/被动),否则会静默失败。务必确保每次重连后都重新调用 set_pasv(),且值与首次一致。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











