如何解决Python3中ftplib批量上传文件时的FTP超时问题?
解决ftplib上传大量文件时的连接超时问题
看到你用ftplib处理上千个文件上传时遇到连接超时的问题,这在批量FTP操作里太常见了——你的现有代码其实有几个可以优化的点,我来一步步帮你调整:
先分析现有代码的问题
你的代码里,一旦某个文件上传出错就直接ftp.quit()+ftp.close(),后续文件没有重新建立连接肯定会报错;另外默认的FTP连接超时可能太短,长时间闲置或者大文件上传时容易触发超时;还有没有重试机制,偶然的网络波动就会导致上传失败。
优化方案和修改后的代码
我会给代码加上超时设置、重试机制、连接保活这几个关键功能,让批量上传更稳定:
import ftplib import os import time def uploader(self, chunk): print("ON UPLOADER", chunk) print("Uploader", self.outer) pnglist = [] csvlist = [] print("Changed") # 先处理本地目录切换 try: base_dir = '/home/ubuntu/rabit' self.outer = os.path.join(base_dir, self.outputdir) os.chdir(self.outer) except Exception as e: print("Directory error:", self.outer) print("Exception:", e) return 1 # 目录有问题直接返回,不用继续 # 定义一个重新建立FTP连接的函数 def get_ftp_connection(): ftp = ftplib.FTP(self.host, timeout=300) # 设置5分钟超时,根据你的需求调整 ftp.login(self.username, self.password) ftp.cwd(self.outputdir) return ftp ftp = get_ftp_connection() retry_count = 3 # 每个文件最多重试3次 files_processed = 0 keep_alive_interval = 50 # 每上传50个文件发送一次保活命令 for file1 in chunk: print("Processing file:", file1) success = False current_retry = 0 while current_retry < retry_count and not success: try: # 定期发送NOOP保持连接活跃 if files_processed % keep_alive_interval == 0 and files_processed > 0: ftp.voidcmd('NOOP') print("Sent NOOP to keep connection alive") with open(file1, 'rb') as f: ftp.storbinary('STOR ' + file1, f) # os.remove(file1) # 建议确认上传成功后再删除,避免误删 print(f"{file1} uploaded successfully") success = True files_processed += 1 # 数据库标记成功 SingletonDecorator( f"UPDATE gdl_input_files SET processed ='4' , errordata='0' WHERE filename='{file1}'", function="insertion" ) except (ftplib.error_temp, ftplib.error_perm, ConnectionResetError, TimeoutError) as e: current_retry += 1 print(f"Error uploading {file1}, retry {current_retry}/{retry_count}: {e}") # 出错后尝试重新连接 if current_retry < retry_count: try: ftp.quit() except: pass # 可能连接已经断开,忽略quit错误 ftp = get_ftp_connection() time.sleep(2) # 重试前等待2秒,避免频繁连接 except Exception as e: print(f"Unexpected error with {file1}: {e}") # 非超时/连接类错误,直接标记失败 SingletonDecorator( f"UPDATE gdl_input_files SET processed ='4' , errordata='1' WHERE filename='{file1}'", function="insertion" ) break # 如果重试多次还是失败,标记错误 if not success: print(f"Failed to upload {file1} after {retry_count} retries") SingletonDecorator( f"UPDATE gdl_input_files SET processed ='4' , errordata='1' WHERE filename='{file1}'", function="insertion" ) # 最后关闭连接 try: ftp.quit() except: ftp.close() return 0
关键优化点说明
- 设置连接超时:初始化FTP时指定
timeout=300(5分钟),避免默认的短超时导致闲置断开。 - 连接保活:每上传50个文件发送
NOOP命令,告诉服务器连接还在活跃,防止被主动断开。 - 重试机制:每个文件最多重试3次,出错后重新建立连接,应对临时的网络波动或服务器繁忙。
- 优雅的错误处理:区分不同类型的错误,只对超时、连接重置这类临时错误重试,其他错误直接标记失败。
- 安全的文件删除:注释掉了
os.remove,建议确认上传成功后再删除,避免上传失败但文件已经被删掉的情况。
内容的提问来源于stack exchange,提问作者chris1234




