使用 SFTP 和 Paramiko Python 获取递归文件夹

Posted

技术标签:

【中文标题】使用 SFTP 和 Paramiko Python 获取递归文件夹【英文标题】:Get Recursive folder using SFTP and Paramiko Python 【发布时间】:2021-12-27 15:14:21 【问题描述】:

尝试实现一个python脚本并将get递归文件夹从远程机器放到本地机器,这段代码适用于复制:放置文件夹和获取文件夹,现在我想创建移动,想法是一旦传输我就删除文件添加行 sftp.remove() 并在帖子末尾获取错误堆栈任何线索吗?

import paramiko
    import os
    from stat import S_ISDIR, S_ISREG  
    
    class MySFTPClient(paramiko.SFTPClient):
            def put_dir(self, source, target):
                    ''' Uploads the contents of the source directory to the target path. The
                        target directory needs to exists. All subdirectories in source are 
                        created under target.
                    '''
                    for item in os.listdir(source):
                        if os.path.isfile(os.path.join(source, item)):
                            self.put(os.path.join(source, item), '%s/%s' % (target, item))
                        else:
                            self.mkdir('%s/%s' % (target, item), ignore_existing=True)
                            self.put_dir(os.path.join(source, item), '%s/%s' % (target, item))
    
            def mkdir(self, path, mode=511, ignore_existing=False):
                    ''' Augments mkdir by adding an option to not fail if the folder exists  '''
                    try:
                        super(MySFTPClient, self).mkdir(path, mode)
                    except IOError:
                        if ignore_existing:
                            pass
                        else:
                            raise
    
    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)
                    print("Removing file :",item.filename)
                    sftp.remove(dest + "/" + item.filename)
                    

将 sftp.remove(dest + "/" + item.filename) 改为 sftp.remove(path + "/" + item.filename) 解决

    transport = paramiko.Transport(('172.31.11.233', 22))
    transport.connect(username='$(ops_unv_cred_user_018f3e16e789465bb5110a90837ce03f)', password='$(ops_unv_cred_pwd_018f3e16e789465bb5110a90837ce03f)')
      
    if 1==1:
        sftp = paramiko.SFTPClient.from_transport(transport)            
        if 0==1:
            sftp.get('/home/karim/EDV','/home/karim/israel')
            print("copied successfully!")                      
        else:
            sftp_get_recursive('/home/karim/EDV', '/home/karim/israel', sftp)
            print("copied successfully!")
            if 1==1:
                print("Listing all files in remote machine where path is => /home/karim/EDV :" )
                print(sftp.listdir('/home/karim/EDV'))
        if 1==1: 
            print("Listing all files in remote machine where path is => /home/karim/EDV :" )
            print(sftp.listdir('/home/karim/EDV'))       
    else:
        sftp = MySFTPClient.from_transport(transport) 
        if 0==1: 
            sftp.put('/home/karim/israel','/home/karim/EDV')
            print("copied successfully!")
           
        else:        
            sftp.mkdir('/home/karim/EDV', ignore_existing=True)
            sftp.put_dir('/home/karim/israel','/home/karim/EDV')
            print("copied successfully!")
    
        if 1==1:   
            print("Listing all files in remote machine where path is => /home/karim/EDV :" )
            print(sftp.listdir('/home/karim/EDV'))
    
    sftp.close()



Traceback (most recent call last):   File "/home/karim/.56ee3cce-0616-4070-bfa5-b5a0f346b2c7.sh", line 64, in <module>
    sftp_get_recursive('/home/karim/EDV', '/home/karim/israel', sftp)   File "/home/karim/.56ee3cce-0616-4070-bfa5-b5a0f346b2c7.sh", line 50, in sftp_get_recursive
    sftp_get_recursive(path + "/" + item.filename, dest + "/" + item.filename, sftp)   File "/home/karim/.56ee3cce-0616-4070-bfa5-b5a0f346b2c7.sh", line 54, in sftp_get_recursive
    sftp.remove(dest + "/" + item.filename)   File "/opt/universal/python/lib/python3.7/site-packages/paramiko/sftp_client.py", line 398, in remove
    self._request(CMD_REMOVE, path)   File "/opt/universal/python/lib/python3.7/site-packages/paramiko/sftp_client.py", line 813, in _request
    return self._read_response(num)   File "/opt/universal/python/lib/python3.7/site-packages/paramiko/sftp_client.py", line 865, in _read_response
    self._convert_status(msg)   File "/opt/universal/python/lib/python3.7/site-packages/paramiko/sftp_client.py", line 894, in _convert_status
    raise IOError(errno.ENOENT, text) FileNotFoundError: [Errno 2] No such file

【问题讨论】:

using paramiko 不是有效的 Python。 您的问题到底是什么? No such file or directory: '/home/karim/EDV'这有什么不清楚的地方? 你是对的,对不起,我使用 Import 代替,只是在发布时出错。所以错误在于 import Paramiko 路径 /home/karim/EDV 存在于远程机器中,包含一些文件和文件夹。似乎它没有通过 os.listdir(target) 【参考方案1】:

从您的 cmets 看来,target 似乎是一个远程路径,尽管它应该是“源”,因为您正在下载。您正在使用带有本地 API 的远程路径,例如 os.listdir。那不行,你应该使用SFTPClient.listdir_attr

有关递归下载的示例,请参阅:Recursive directory download with Paramiko?

【讨论】:

pysftp的问题,是从windows下载递归文件夹到linux不行吗? 我不明白你的评论。你不是从 Windows 下载到 Linux,对吧? (而且 pysftp 从 Linux 下载到 Windows 有问题,而不是从 Windows 到 Linux)。而且我不建议您使用 pysftp。我发布的链接包含经过微小修改(在那里描述)的代码,也适用于 Paramiko。请点击链接。 或见***.com/a/53556194/850848#53556194 感谢您的提示,但是您如何使用 get_r_portable 呢? transport = paramiko.Transport(('$ops_sftp_hostname', 22)) transport.connect(username='$_credentialUser('$ops_sftp_credential')', password='$_credentialPwd('$ops_sftp_credential ')') sftp = paramiko.SFTPClient.from_transport(transport) sftp.get_r_portable('$ops_sftp_remote_path','$ops_sftp_local_path') sftp.close() 我得到:回溯(最近一次通话最后):文件“/home/karim/.f041aed9-fe22-4371-b350-cbecbb5ce567.sh”,第 21 行,在 get_r_portable(sftp ,'/home/karim/EDV','/home/karim/nouveau') 文件“/home/karim/.f041aed9-fe22-4371-b350-cbecbb5ce567.sh”,第 15 行,在 get_r_portable get_r_portable(sftp, remotepath , localpath, preserve_mtime) NameError: name 'preserve_mtime' is not defined

以上是关于使用 SFTP 和 Paramiko Python 获取递归文件夹的主要内容,如果未能解决你的问题,请参考以下文章

Python学习—paramiko模块实现简单的ssh与sftp

Python paramiko模块使用解析实现sftp

使用 Paramiko 在 Python 中列出与通配符匹配的 SFTP 服务器上的文件

使用 ppk 文件上传 Paramiko sftp [重复]

python paramiko模块sftp异常:paramiko.ssh_exception.SSHException: EOF during negotiation

如何使用 Python SFTP/Paramiko 将 zip 文件从一台服务器传输到另一台服务器