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

Django使用ftplib连接FTP上传文件是否可行?如何解决相关报错

问题根因

这套借助ftplib+Django后台异步任务跨服务传文件的方案完全可行,你两次上传失败的核心原因都是参数传递错误,和框架、组件本身的能力无关:

  1. 第一版代码触发AttributeError: 'str' object has no attribute 'read',是因为ftp.storbinary要求第二个参数传入支持read()方法的二进制类文件对象,而你写的file = os.path.join(folder, filename)只是本地文件的路径字符串,根本不是打开的文件句柄,ftplib尝试调用字符串的read方法必然报错。另外这段代码里filename变量没有在函数入参或者内部定义,本身也会触发NameError。
  2. 第二版用PIL+BytesIO处理的代码逻辑方向是对的,但最后传参传错了:你把处理好的图片写入了BytesIO实例b,也执行了b.seek(0)把流指针移到了开头,结果传给storbinary的还是PIL打开的file对象,不是准备好的字节流b,自然上传失败。
可直接运行的实现代码

场景1:直接上传本地原文件,不需要额外处理

@background(schedule=1)
def uploadToFTP(folder, filename_list):
    """
    异步上传本地文件到FTP服务器
    :param folder: 本地文件存储的绝对路径
    :param filename_list: 本次需要上传的文件名列表
    """
    print("-------------------Start FTP Task ----------------------------")
    # 建立FTP连接,配置超时避免僵死连接
    ftp = FTP(
        host=conf_settings.FTP_DOMAIN,
        user=conf_settings.FTP_USER,
        passwd=conf_settings.FTP_PASSWORD,
        timeout=30
    )
    # 开启被动模式,适配绝大多数FTP服务器的防火墙规则
    ftp.set_pasv(True)

    for filename in filename_list:
        local_path = os.path.join(folder, filename)
        # 必须以二进制只读模式打开本地文件,拿到合法的文件对象
        with open(local_path, 'rb') as f:
            ftp.storbinary(f'STOR {filename}', fp=f, blocksize=102400)

    # 上传完成主动关闭连接,避免连接泄漏
    ftp.quit()

场景2:图片经PIL处理后直接从内存上传,不生成本地临时文件

import io
from PIL import Image

@background(schedule=1)
def uploadProcessedImgToFTP(folder, img_name_list):
    print("-------------------Start Processed Image FTP Task ----------------------------")
    ftp = FTP(
        host=conf_settings.FTP_DOMAIN,
        user=conf_settings.FTP_USER,
        passwd=conf_settings.FTP_PASSWORD,
        timeout=30
    )
    ftp.set_pasv(True)

    for img_name in img_name_list:
        local_img_path = os.path.join(folder, img_name)
        with Image.open(local_img_path) as img:
            # 可按需插入图片处理逻辑:裁剪、压缩、加水印、转格式等
            img_buffer = io.BytesIO()
            img.save(img_buffer, format="JPEG", quality=90)
            # 关键操作:将字节流指针重置到起始位置,否则会读取到空内容
            img_buffer.seek(0)
            # 注意传入的是准备好的内存字节流对象,不是PIL的Image实例
            ftp.storbinary(f'STOR {img_name}', fp=img_buffer, blocksize=102400)
            img_buffer.close()

    ftp.quit()
避坑提示
  • 不要在任务函数内部使用未定义的变量(比如第一版代码里的filename),后台调度环境拿不到请求上下文里的临时变量,很容易触发变量未定义错误,所有任务需要的参数都要通过入参显式传入。
  • 如果需要上传到FTP的指定子目录,在执行storbinary前先调用ftp.cwd(远程目标目录路径)切换工作目录,否则文件会默认传到FTP账号的根目录。
  • 如果FTP服务器限制了IP连接频率,不要在循环里反复新建/关闭FTP连接,复用同一个连接批量上传即可。
  • 不要忘了给打开的本地文件、内存流、FTP连接做资源释放,用with上下文或者手动调用close/quit都可以,不然任务跑久了会出现文件句柄泄漏、连接数超限的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 21:09:59