
本文详解在 Paramiko 的 SFTPClient 中准确判断远程路径是否为目录的正确方法,重点解决 SFTPAttributes 对象无 isdir() 或 st_isdir() 方法导致的 AttributeError,并提供健壮、可复用的递归下载实现。
本文详解在 paramiko 的 sftpclient 中准确判断远程路径是否为目录的正确方法,重点解决 `sftpattributes` 对象无 `isdir()` 或 `st_isdir()` 方法导致的 attributeerror,并提供健壮、可复用的递归下载实现。
Paramiko 的 SFTPClient.stat() 方法返回的是 SFTPAttributes 实例,其属性设计严格对标 Python 原生 os.stat() 的返回结构(如 st_mode, st_size, st_mtime 等),但不直接提供 isdir()、isfile() 等便捷方法。因此,直接调用 stat(...).isdir() 或 stat(...).st_isdir() 会触发 AttributeError——这是初学者常见误区。
正确做法是借助标准库 stat 模块中的位掩码判断函数。SFTPAttributes.st_mode 字段包含了完整的 Unix 文件类型与权限信息,只需用 stat.S_ISDIR(mode) 即可安全、高效地判定是否为目录:
import stat
# ✅ 正确:使用 stat.S_ISDIR 判断
sftp_attr = self.sftp_instance.stat(remote_path)
if stat.S_ISDIR(sftp_attr.st_mode):
print(f"{remote_path} 是一个目录")
else:
print(f"{remote_path} 是一个文件")⚠️ 注意事项:
- stat.S_ISDIR() 接收的是 st_mode 整数值(非 SFTPAttributes 对象本身);
- 不要混淆 self.sftp_instance.listdir()(仅列出当前目录内容,不接受路径参数)与 self.sftp_instance.listdir_attr(path)(可传入路径,返回带属性的列表,更高效);
- self.sftp_instance.stat(path) 要求 path 为绝对路径或相对于当前工作目录的有效路径;若传入相对名(如 "logs"),需确保当前工作目录已正确定位。
以下是一个修复后的递归下载函数示例,整合了路径类型判断、错误处理与路径切换逻辑:
import os
import stat
from paramiko import SFTPClient
def download_files(self, local_dir: str):
if not isinstance(self.sftp_instance, SFTPClient):
print("SFTP connection not established. Please connect first.")
return
try:
current_dir = self.sftp_instance.getcwd()
local_path = os.path.join(local_dir, os.path.basename(current_dir))
os.makedirs(local_path, exist_ok=True)
# 推荐:使用 listdir_attr 获取含属性的条目,避免多次 stat 调用
for attr in self.sftp_instance.listdir_attr():
item_name = attr.filename
remote_path = os.path.join(current_dir, item_name)
item_local_path = os.path.join(local_path, item_name)
# ✅ 核心判断:使用 stat.S_ISDIR + st_mode
if stat.S_ISDIR(attr.st_mode):
print(f"进入子目录: {item_name}")
self.sftp_instance.chdir(item_name)
self.download_files(local_path) # 递归下载子目录
self.sftp_instance.chdir("..") # 返回上级
else:
try:
self.sftp_instance.get(remote_path, item_local_path)
print(f"✓ 下载文件: {item_name}")
except Exception as e:
print(f"✗ 下载失败 {item_name}: {e}")
except Exception as e:
print(f"操作异常: {e}")该实现显著提升了健壮性:
✅ 避免重复调用 stat()(listdir_attr() 已含完整属性);
✅ 使用标准 stat.S_ISDIR 替代不存在的方法;
✅ 显式异常捕获,区分连接、权限、路径等不同错误场景;
✅ 兼容 Paramiko ≥3.0(st_mode 属性始终可用,API 稳定)。
总结:Paramiko 的路径类型判断本质是 Unix 模式位解析,而非面向对象的链式调用。牢记 import stat + stat.S_ISDIR(attr.st_mode) 这一黄金组合,即可彻底规避 AttributeError,并写出符合生产环境要求的 SFTP 交互逻辑。

















