【问题标题】:Recursive directory download with Paramiko?使用 Paramiko 进行递归目录下载?
【发布时间】:2011-10-04 05:30:04
【问题描述】:

我想通过 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()

那么我怎么知道一个项目是一个文件还是一个目录呢?

【问题讨论】:

标签: python ssh paramiko


【解决方案1】:

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 风格的外观和感觉,并支持递归操作。见

或者查看我对Python pysftp get_r from Linux works fine on Linux but not on Windows的回复。

但是 pysftp 似乎是一个废弃的项目,所以你最好坚持使用 Paramiko。

【讨论】:

    【解决方案2】:

    对 Dan LaManna 的答案的小幅更新,将于 2021 年生效。

    import paramiko
    import os
    from stat import S_ISDIR, S_ISREG    
    
    def sftp_get_recursive(path, dest, sftp):
        item_list = sftp.listdir_attr(path)
        dest = str(dest)
        if not os.path.isdir(dest):
            os.makedirs(dest, exist_ok=True)
        for item in item_list:
            mode = item.st_mode
            if S_ISDIR(mode):
                sftp_get_recursive(path + "/" + item.filename, dest + "/" + item.filename, sftp)
            else:
                sftp.get(path + "/" + item.filename, dest + "/" + item.filename)
    
    transport = paramiko.Transport((host, port))
    transport.connect(username=username, password=password)
    sftp = paramiko.SFTPClient.from_transport(transport)
    sftp_get_recursive(remote_path, local_path, sftp)
    sftp.close()
    

    【讨论】:

      【解决方案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)
      

      【讨论】:

      • 根据 2021 年的这个答案需要一些更新;我发布了更新的答案。
      【解决方案4】:

      stat() 方法以及其他属性返回权限。 d(例如drwxrwxrwx)表示是目录。

      例如:

      dir = oct(sftp.stat(path).st_mode)
      print dir[0:2]
      

      输出解释: 01 先进先出 02字特殊 04目录 06块特价 10个常规文件 12 符号链接 14个插座

      【讨论】:

        【解决方案5】:
        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 连接。

        【讨论】:

        • 现在无法测试,但这似乎将最后一个缺失的部分添加到完整的答案中。将接受的标志移到此处。
        【解决方案6】:

        您可以使用 sftp 对象的 stat() 方法:

        http://www.lag.net/paramiko/docs/paramiko.SFTPClient-class.html

        【讨论】:

        • 啊,是的,可能就是这样。尚未对其进行测试,但幸运的是,目录标志可以从 SFTPAttributes.st_mode 中解析出来。现在我只需要研究该模式值中隐藏了哪些标志...
        【解决方案7】:

        如果你使用 Linux 或类 Unix。您可以使用带有 popen 的“文件”实用程序。 或者简单的你可以使用 os.path.isdir() =)

        【讨论】:

        • 请正确英语。除此之外,使用file 来测试某个东西是否是文件夹非常麻烦。并在远程文件上使用os.path.isdir()..?
        猜你喜欢
        • 2023-03-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-29
        • 1970-01-01
        • 1970-01-01
        • 2011-05-23
        相关资源
        最近更新 更多