Python使用pysftp批量上传文件到SFTP服务器报错排查
问题根因
- 核心错误是路径拼接缺失:
os.listdir('C:/Test/')仅返回目录下的文件名,不包含C:/Test/前缀,调用conn.put(file)时,程序会在Python脚本的当前运行目录下找对应的文件,根本读不到C:/Test/下的真实文件,直接触发上传失败。你单文件上传时如果写了完整文件路径可以正常运行,就是这个原因。 - 连接管理逻辑有缺陷:如果SFTP连接建立失败,
conn变量根本不会被初始化,后续直接调用conn.cd('/')会直接抛变量不存在的错误;就算连接建立成功,上传过程中触发异常后连接会非正常断开,pysftp在自动销毁连接对象时就会抛出你看到的'NoneType' object has no attribute 'time'异常,这个是连带报错,不是问题根源。 - 异常捕获逻辑太粗糙:所有异常都只打印固定提示,吞掉了具体错误信息,根本没法定位真实失败原因;同时没有过滤本地目录下的子文件夹,遍历到文件夹时调用put接口也会触发上传失败。
修复后代码
import pysftp import os # 替换为实际的SFTP配置信息 host = "你的SFTP服务器地址" port = 22 username = "你的登录用户名" password = "你的登录密码" local_dir = "C:/Test/" remote_dir = "/" cnopts = pysftp.CnOpts() cnopts.hostkeys = None # 用上下文管理器自动维护连接生命周期,异常时也能正常关闭连接 with pysftp.Connection( host=host, port=port, username=username, password=password, cnopts=cnopts ) as conn: print("SFTP连接建立成功") conn.cd(remote_dir) for filename in os.listdir(local_dir): # 拼接本地文件的完整绝对路径,解决找不到文件的核心问题 local_file = os.path.join(local_dir, filename) # 跳过子目录等非文件项,避免上传目录触发报错 if not os.path.isfile(local_file): print(f"跳过非文件项:{filename}") continue try: conn.put(local_file) print(f"上传成功:{filename}") except Exception as e: print(f"上传失败:{filename},错误详情:{str(e)}")
关键修复点
- 补全本地文件路径:通过
os.path.join()拼接目录路径和文件名,保证程序能正确读到本地待上传文件 - 用
with语句管理SFTP连接:无论代码运行正常还是抛出异常,都会自动正常关闭连接,彻底解决连接析构时抛出的NoneType连带报错 - 增加文件类型校验:遍历过程中跳过子文件夹、快捷方式等非文件项,避免无效上传请求
- 细化异常输出:捕获上传异常时打印具体错误信息,方便快速定位是文件占用、权限不足还是路径错误问题
- 把连接操作纳入上下文管理范围:避免连接建立失败后调用不存在的连接对象触发低级错误
内容的提问来源于stack exchange,提问作者Kirill
相关产品推荐
相关产品推荐

