最简上传代码为:pip install pysftp 后,用 with pysftp.Connection(...) as sftp: sftp.put(local_path, remote_path);生产环境须校验 host key,密钥需 chmod 600,注意远程路径以 / 开头才为绝对路径。

用 pysftp 连接并上传单个文件最简路径
直接能跑通的最小可行代码就是:先装包,再连,再 put()。注意默认不校验 host key,生产环境必须显式处理,否则会静默失败或报错。
常见错误现象:Connection closed by remote host 或 Authentication failed,多数是密码错、密钥权限不对(比如私钥没 chmod 600),或远程用户没写入权限。
- 安装:
pip install pysftp(注意它底层依赖paramiko,会自动装) - 基础上传示例:
import pysftp with pysftp.Connection('192.168.1.100', username='user', password='pass') as sftp: sftp.put('/local/path/file.txt', '/remote/path/file.txt') - 若用密钥登录,把
password=...换成private_key='/path/to/id_rsa';密钥带密码则加private_key_pass='key_pass' - 上传前建议先
sftp.isdir('/remote/path')检查目录是否存在,否则put()会报IOError: Failure
批量上传 + 自动创建远程目录用 os.walk() 和 sftp.makedirs()
单纯循环 put() 会卡在子目录不存在的问题上。pysftp 没有递归创建目录的内置方法,得自己拆路径逐级判断。
关键点:远程路径分隔符固定是 /,和本地 os.sep 无关;sftp.makedirs() 是 pysftp 0.2.9+ 才支持的,旧版本得手动 mkdir。
- 遍历本地目录示例:
import os import pysftp <p>with pysftp.Connection(...) as sftp: for root, dirs, files in os.walk('/local/dir'): for file in files: local_path = os.path.join(root, file)</p><h1>转成相对路径,再拼远程根目录</h1><pre class="brush:php;toolbar:false;"> rel_path = os.path.relpath(local_path, '/local/dir') remote_path = '/remote/root/' + rel_path.replace(os.sep, '/') # 确保远程父目录存在 remote_dir = os.path.dirname(remote_path) if not sftp.exists(remote_dir): sftp.makedirs(remote_dir) sftp.put(local_path, remote_path) - 注意
sftp.exists()对文件和目录都返回True,所以判断目录存在与否不能只靠它;sftp.isdir()更准 - 大量小文件时,每次
put()都有连接开销,但pysftp不支持管道式批量传输,别硬套tar流——容易因超时中断且难调试
上传失败重试 + 超时控制必须手动加,pysftp 不自带
pysftp.Connection 的 timeout 参数只管建立连接阶段,传输过程超时、卡死、断连后自动重连,全得自己兜底。
典型表现:上传大文件时网络抖动,put() 卡住不动,程序假死;或者抛出 socket.timeout 但没被 pysftp 捕获,直接崩。
- 给
put()加超时,用signal.alarm()(Linux/macOS)或封装线程 +threading.Event(跨平台) - 简单重试逻辑示例(仅限幂等操作,如覆盖上传):
import time for i in range(3): try: sftp.put(local_path, remote_path, callback=progress_cb) break except (OSError, IOError) as e: if i == 2: raise e time.sleep(2 ** i) # 指数退避 -
callback参数可传进度函数,比如打印已传字节数,但别在里面做耗时操作,否则拖慢上传 - 别依赖
sftp.stat()做上传后校验——SFTP 服务器可能缓存 stat 结果,刚传完立刻查可能 size 还是 0
为什么不用 paramiko 原生 API?
直接用 paramiko.SFTPClient 确实更底层可控,比如能设 get_channel().settimeout() 精确控传输超时,也能捕获 SFTPError 细分错误码。但代价是代码量翻倍,且多数人不需要那么细的控制。
真正需要切到 paramiko 的场景只有两个:一是 pysftp 的 makedirs() 在某些老旧 OpenSSH 版本上失效;二是必须用 asyncio 做并发上传(pysftp 全同步阻塞)。
- 如果选
paramiko,别漏掉transport.set_keepalive(30),否则空闲连接容易被中间设备断开 -
pysftp的Connection类是对paramiko.Transport+SFTPClient的封装,它的get()/put()底层就是调的paramiko方法,性能无差异 - 一个易忽略点:所有 SFTP 上传路径都是相对于远程用户的 home 目录,除非你用绝对路径(以
/开头)。用相对路径时,别假设它从/开始
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











