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

Python ftplib上传超时且无法续传问题求助

解决不稳定FTP服务器大文件上传超时且无法续传的问题

嘿,我来帮你搞定这个FTP续传失效的麻烦!我之前在处理不稳定服务器的大文件上传时也踩过类似的坑,你的代码思路是对的,但几个关键细节没处理到位,导致超时后没法续传。咱们一步步来排查和修复:

核心问题分析

你的代码里已经有了进度跟踪器,但缺少以下几个关键环节:

  • 超时机制缺失:默认的ftplib超时设置太短,或者没有处理传输过程中的socket超时异常
  • 续传校验逻辑不完善:没有准确获取服务器上已上传的文件大小,本地文件指针也没正确定位到续传位置
  • 被动模式未启用:不稳定网络下,主动模式(PORT)容易被防火墙拦截,被动模式(PASV)更可靠
  • 异常重试机制不足:遇到超时、连接重置等异常时,直接退出而不是尝试重新连接续传

修复后的完整代码示例

#!/usr/bin/env python3
import ftplib
import os
import sys
import time
import socket
from configparser import ConfigParser

class FtpUploadTracker:
    def __init__(self, total_size, uploaded_size=0):
        self.size_written = uploaded_size
        self.total_size = total_size
        self.last_shown_percent = 0

    def handle(self, block):
        self.size_written += len(block)  # 这里别用固定1024,block大小可能不固定
        percent_complete = round((self.size_written / self.total_size) * 100, 1)
        if percent_complete > self.last_shown_percent:
            print(f"上传进度: {percent_complete}% ({self.size_written}/{self.total_size} bytes)", end='\r')
            self.last_shown_percent = percent_complete

def upload_file_with_resume(ftp_host, ftp_user, ftp_pass, local_file_path, remote_file_path, max_retries=5, timeout=300):
    local_file_size = os.path.getsize(local_file_path)
    uploaded_size = 0

    for retry in range(max_retries):
        try:
            # 初始化FTP连接,设置超时
            ftp = ftplib.FTP(ftp_host, timeout=timeout)
            ftp.login(ftp_user, ftp_pass)
            ftp.set_pasv(True)  # 启用被动模式,适配不稳定网络

            # 检查服务器上是否已有该文件,获取已上传大小
            try:
                remote_file_size = ftp.size(remote_file_path)
                # 校验本地和远程文件大小,避免续传错误
                if remote_file_size < local_file_size:
                    uploaded_size = remote_file_size
                    print(f"检测到已上传 {uploaded_size} bytes,开始续传...")
                else:
                    print("远程文件已完整,无需上传")
                    return
            except ftplib.error_perm:
                # 文件不存在,从头开始上传
                uploaded_size = 0
                print("远程文件不存在,开始全新上传...")

            # 打开本地文件,定位到续传位置
            with open(local_file_path, 'rb') as f:
                f.seek(uploaded_size)
                tracker = FtpUploadTracker(local_file_size, uploaded_size)
                # 使用STOR命令续传,注意要加REST参数指定起始位置
                ftp.storbinary(f"STOR {remote_file_path}", f, blocksize=1024*1024, callback=tracker.handle, rest=uploaded_size)
            
            print("\n上传完成!")
            ftp.quit()
            return

        except (socket.timeout, ftplib.error_temp, ConnectionResetError) as e:
            print(f"\n上传出错: {str(e)},第 {retry+1}/{max_retries} 次重试...")
            time.sleep(5)  # 重试前等待5秒
            continue
        except Exception as e:
            print(f"\n未知错误: {str(e)},终止上传")
            raise

    print(f"\n已重试 {max_retries} 次仍失败,请检查服务器连接或文件")

if __name__ == "__main__":
    # 这里可以替换成你的配置,或者从ConfigParser读取
    config = {
        'ftp_host': 'your-ftp-host',
        'ftp_user': 'your-ftp-user',
        'ftp_pass': 'your-ftp-pass',
        'local_file': '/path/to/your/large-file',
        'remote_file': '/remote/path/to/large-file'
    }

    upload_file_with_resume(
        config['ftp_host'],
        config['ftp_user'],
        config['ftp_pass'],
        config['local_file'],
        config['remote_file']
    )

关键修复点解释

  1. 完善进度跟踪器:用len(block)替代固定的1024,因为storbinary的block大小可能因网络情况变化,避免进度计算错误
  2. 超时与被动模式:初始化FTP时设置全局超时,同时启用被动模式set_pasv(True),解决不稳定网络下的连接问题
  3. 续传校验逻辑:通过ftp.size()获取远程文件大小,只有当远程文件小于本地时才续传,避免覆盖已完成的文件
  4. 异常重试机制:捕获socket.timeout、ConnectionResetError等常见网络异常,最多重试5次,每次重试前等待几秒
  5. 正确的续传命令:使用rest=uploaded_size参数告诉FTP服务器从指定位置开始接收数据,这是断点续传的核心

额外建议

  • 如果服务器支持,可以开启FTP的SSL/TLS加密(使用ftplib.FTP_TLS),提升传输稳定性和安全性
  • 对于超大文件(比如10GB以上),可以考虑分块上传后在服务器合并,但需要服务器支持文件操作命令
  • 可以增加日志记录,把每次重试的时间、错误信息保存到文件,方便后续排查问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:26:38