核心概念
paramiko 是一个纯 Python 实现的 SSHv2 协议库,它为你提供了类似 OpenSSH 客户端的功能,让你可以在 Python 脚本中安全地连接到远程服务器,并执行命令、传输文件等。

文件传输主要通过 SFTP (SSH File Transfer Protocol) 实现,paramiko 通过 SFTPClient 类来封装 SFTP 的所有操作。
安装 Paramiko
如果你的环境中还没有安装 paramiko,可以使用 pip 进行安装:
pip install paramiko
编写上传代码
我们将创建一个 Python 脚本,该脚本会将本地的一个文件上传到远程服务器的指定目录。
完整代码示例
这是一个功能完整、带有错误处理的示例。

import paramiko
import os
def upload_file_via_sftp(
hostname: str,
port: int,
username: str,
password: str,
local_path: str,
remote_path: str
):
"""
使用 Paramiko 通过 SFTP 上传文件到远程服务器。
:param hostname: 远程服务器地址 (IP 或域名)
:param port: SSH 端口号,通常是 22
:param username: SSH 用户名
:param password: SSH 密码
:param local_path: 本地文件的完整路径
:param remote_path: 远程服务器上目标文件的完整路径
"""
# 1. 创建 SSH 客户端对象
ssh = paramiko.SSHClient()
# 2. 自动添加服务器的 host key (不安全,仅用于测试环境)
# 在生产环境中,应该使用 ssh.load_host_keys() 或设置 known_hosts 文件
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
# 3. 连接远程服务器
print(f"正在连接到 {hostname}...")
ssh.connect(hostname=hostname, port=port, username=username, password=password)
print("连接成功!")
# 4. 创建 SFTP 客户端
sftp = ssh.open_sftp()
print("SFTP 会话已开启。")
# 5. 上传文件
# sftp.put(local_file, remote_file)
print(f"开始上传: {local_path} -> {remote_path}")
sftp.put(local_path, remote_path)
print("文件上传成功!")
except paramiko.AuthenticationException:
print("认证失败,请检查用户名和密码。")
except paramiko.SSHException as e:
print(f"SSH 连接或操作出错: {e}")
except FileNotFoundError:
print(f"本地文件未找到: {local_path}")
except Exception as e:
print(f"发生未知错误: {e}")
finally:
# 6. 关闭 SFTP 和 SSH 连接
if 'sftp' in locals() and sftp:
sftp.close()
print("SFTP 连接已关闭。")
if ssh:
ssh.close()
print("SSH 连接已关闭。")
# --- 使用示例 ---
if __name__ == "__main__":
# --- 请替换为你的服务器信息 ---
HOSTNAME = "your_server_ip_or_domain.com"
PORT = 22
USERNAME = "your_ssh_username"
PASSWORD = "your_ssh_password"
# --- 请替换为你的文件路径 ---
# 本地文件路径
LOCAL_FILE_PATH = "/path/to/your/local_file.txt"
# 远程文件路径 (建议使用绝对路径)
# 如果远程目录不存在,put() 操作会失败
REMOTE_FILE_PATH = "/home/your_username/remote_file.txt"
# 调用函数执行上传
upload_file_via_sftp(
hostname=HOSTNAME,
port=PORT,
username=USERNAME,
password=PASSWORD,
local_path=LOCAL_FILE_PATH,
remote_path=REMOTE_FILE_PATH
)
代码详解
-
paramiko.SSHClient()这是创建 SSH 客户端连接的入口对象。
-
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())- 安全警告: 这行代码会自动接受并保存服务器的 SSH 密钥(Host Key),这在测试或个人开发环境中很方便,但在生产环境中是危险的,因为它可能让你遭受“中间人攻击”(Man-in-the-Middle Attack)。
- 生产环境建议:
- 方法一: 在你的本地机器上,确保你已经通过
ssh-keyscan或手动连接过服务器,服务器的密钥已经保存在~/.ssh/known_hosts文件中。paramiko默认会检查这个文件。 - 方法二: 在代码中显式加载密钥文件。
# 加载 known_hosts 文件 ssh.load_host_keys(os.path.expanduser('~/.ssh/known_hosts')) # 如果服务器密钥不在文件中,连接会失败
- 方法一: 在你的本地机器上,确保你已经通过
-
ssh.connect(...)
(图片来源网络,侵删)- 这是建立到服务器的实际连接。
hostname: 服务器地址。port: SSH 端口,默认是 22。username: 你的登录用户名。password: 你的登录密码。
-
ssh.open_sftp()- 在已建立的 SSH 连接上,开启一个 SFTP 会话,并返回一个
SFTPClient对象,我们用它来处理所有文件传输相关操作。
- 在已建立的 SSH 连接上,开启一个 SFTP 会话,并返回一个
-
sftp.put(local_path, remote_path)- 这是上传文件的核心方法。
local_path: 你想上传的本地文件的绝对路径或相对于当前工作目录的路径。remote_path: 文件在远程服务器上保存的绝对路径。- 注意:
remote_path中指定的目录不存在,sftp.put()操作会失败并抛出IOError,你需要确保目标目录已经存在,或者先创建它。
-
sftp.close()和ssh.close()- 非常重要: 在
finally块中关闭连接,确保无论操作成功还是失败,网络资源都能被正确释放,先关闭 SFTP,再关闭 SSH。
- 非常重要: 在
进阶用法与最佳实践
使用 SSH 密钥认证(更安全)
在生产环境中,强烈推荐使用 SSH 密钥对进行认证,而不是密码。
# ... 在 ssh.connect() 之前 ...
# 加载私钥文件
private_key_path = '/path/to/your/private_key'
private_key = paramiko.RSAKey.from_private_key_file(private_key_path)
try:
# 在 connect 方法中传入密钥
ssh.connect(hostname=hostname, port=port, username=username, pkey=private_key)
# ... 后续代码相同 ...
创建远程目录
如果目标目录不存在,可以先创建它。SFTPClient 提供了 mkdir 方法。
# 在 sftp.put() 之前,确保目录存在
remote_dir = os.path.dirname(remote_path)
try:
sftp.stat(remote_dir) # 检查目录是否存在
except IOError:
print(f"远程目录 {remote_dir} 不存在,正在创建...")
sftp.mkdir(remote_dir) # 创建目录
显示上传进度
sftp.put() 本身不直接提供回调函数来显示进度,但我们可以通过一个技巧来实现:在循环中分块传输文件,并计算已传输的字节数。
def sftp_upload_with_progress(sftp, local_path, remote_path, chunk_size=8192):
file_size = os.path.getsize(local_path)
uploaded = 0
with open(local_path, 'rb') as f:
with sftp.file(remote_path, 'wb') as remote_file:
while True:
chunk = f.read(chunk_size)
if not chunk:
break
remote_file.write(chunk)
uploaded += len(chunk)
progress = (uploaded / file_size) * 100
print(f"\r上传进度: {progress:.2f}%", end='', flush=True)
print("\n上传完成!")
# 在你的主函数中替换 sftp.put()
# sftp_upload_with_progress(sftp, local_path, remote_path)
处理文件名中的空格和特殊字符
paramiko 的路径处理通常比较健壮,但为了确保万无一失,最好将路径作为字符串处理,并确保它们是绝对路径,避免在路径中包含可能被 shell 误解的字符。
常见问题排查
AuthenticationException: 认证失败,检查用户名、密码或密钥是否正确。SSHException: 连接被拒绝或服务器配置问题,检查服务器是否运行 SSH 服务,防火墙是否开放了指定端口。FileNotFoundError: 本地文件路径错误。IOError: [Errno 2] No such file or directory: 远程目录不存在,确保在上传前创建好远程目录。Permission denied (publickey,password).: 服务器拒绝了你的认证方式,如果你使用的是密码,请确认用户密码正确且有权限写入目标目录,如果你使用的是密钥,请确认密钥已正确添加到服务器的~/.ssh/authorized_keys文件中,并且文件权限正确(authorized_keys文件权限为 600,.ssh目录权限为 700)。
