使用Paramiko进行递归目录下载?
我想通过SSH下载一个内容未知的目录,并且一直在尝试使用Paramiko。我看到过一些关于如何上传目录的例子,但没有找到关于递归下载的例子。
我可以列出目录中的所有项目,但还没有找到判断某个项目是文件(可以下载)还是目录(需要递归调用)的方法。
transport = paramiko.Transport((MY_IP, 22))
transport.connect(username=MY_NAME, password=MY_PASS)
sftp = paramiko.SFTPClient.from_transport(transport)
file_list = sftp.listdir(path='/home/MY_HOME_DIR')
for item in file_list:
# Here is an item name... but is it a file or directory?
print(item)
sftp.close()
transport.close()
那么我怎么知道一个项目是文件还是目录呢?
8 个回答
3
这是一个老问题,但我想出了一个解决办法,效果还不错。虽然有点儿不够规范(比如类型转换和斜杠之类的),但确实能用。
请注意,这里使用了 fabric.api.local
来在目标位置创建目录。
def sftp_get_recursive(path, dest, sftp=sftp):
item_list = sftp.listdir(path)
dest = str(dest)
if not os.path.isdir(dest):
local("mkdir %s" % dest)
for item in item_list:
item = str(item)
if is_directory(path + "/" + item, sftp):
sftp_get_recursive(path + "/" + item, dest + "/" + item, sftp)
else:
sftp.get(path + "/" + item, dest + "/" + item)
4
Paramiko不支持递归操作。
不过,自己实现这个功能其实很简单:
import os
from stat import S_ISDIR, S_ISREG
def get_r_portable(sftp, remotedir, localdir):
for entry in sftp.listdir_attr(remotedir):
remotepath = remotedir + "/" + entry.filename
localpath = os.path.join(localdir, entry.filename)
mode = entry.st_mode
if S_ISDIR(mode):
try:
os.mkdir(localpath)
except OSError:
pass
get_r_portable(sftp, remotepath, localpath)
elif S_ISREG(mode):
sftp.get(remotepath, localpath)
你也可以使用pysftp。它是一个封装了Paramiko的库,看起来更像Python的风格,并且支持递归操作。你可以查看:
pysftp.Connection.put_r()
,这个方法可以用来上传文件。pysftp.Connection.get_r()
,这个方法可以用来下载文件。
或者你可以看看我对Python pysftp在Linux上正常工作,但在Windows上不行的回答。
不过,pysftp似乎是一个被遗弃的项目,所以你最好还是继续使用Paramiko。
12
from stat import S_ISDIR
def isdir(path):
try:
return S_ISDIR(sftp.stat(path).st_mode)
except IOError:
#Path does not exist, so by definition not a directory
return False
...假设 sftp
是一个已经打开的 Paramiko SFTP 连接。