在Python中使用Paramiko进行递归目录复制

发布于 2021-01-29 16:51:37

我是Python脚本的新手。我需要将几个文件夹从本地计算机(Windows)复制到Linux服务器。到目前为止,我正在通过打开WinSCP控制台来复制文件夹。我需要使这个过程自动化。我已经使用Paramiko模块库在Python中编写了以下代码。

import paramiko
import os
transport = paramiko.Transport(('10.10.10.10', 22))
transport.connect(username='weblogic', password='weblogic')
sftp = paramiko.SFTPClient.from_transport(transport)
filepath = '/apps/logs'
localpath = 'C:\\Users\\Public\\test'
sftp.put(localpath,filepath)

上面的不能正常工作,并给出下面的错误。您能帮我将Windows路径中存在的文件夹复制C:\Users\Public\test到Linux服务器路径/apps/logs吗?

Traceback (most recent call last):
  File "C:\Users\Desktop\python\execute_script.py", line 28, in <module>
    sftp.put(localpath,filepath)
  File "C:\Python27\lib\paramiko\sftp_client.py", line 548, in put
    fl = file(localpath, 'rb')
IOError: [Errno 13] Permission denied: 'C:\\Users\\Public\\test'
关注者
0
被浏览
49
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    请从链接https://gist.github.com/johnfink8/2190472检查以下代码。我已经put_all在代码段中使用过方法。

    import paramiko
    import socket
    import os
    from stat import S_ISDIR
    
    class SSHSession(object):
        # Usage:
        # Detects DSA or RSA from key_file, either as a string filename or a
        # file object.  Password auth is possible, but I will judge you for 
        # using it. So:
        # ssh=SSHSession('targetserver.com','root',key_file=open('mykey.pem','r'))
        # ssh=SSHSession('targetserver.com','root',key_file='/home/me/mykey.pem')
        # ssh=SSHSession('targetserver.com','root','mypassword')
        # ssh.put('filename','/remote/file/destination/path')
        # ssh.put_all('/path/to/local/source/dir','/path/to/remote/destination')
        # ssh.get_all('/path/to/remote/source/dir','/path/to/local/destination')
        # ssh.command('echo "Command to execute"')
    
        def __init__(self,hostname,username='root',key_file=None,password=None):
            #
            #  Accepts a file-like object (anything with a readlines() function)  
            #  in either dss_key or rsa_key with a private key.  Since I don't 
            #  ever intend to leave a server open to a password auth.
            #
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.sock.connect((hostname,22))
            self.t = paramiko.Transport(self.sock)
            self.t.start_client()
            keys = paramiko.util.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
            key = self.t.get_remote_server_key()
            # supposed to check for key in keys, but I don't much care right now to find the right notation
            if key_file is not None:
                if isinstance(key,str):
                    key_file=open(key,'r')
                key_head=key_file.readline()
                key_file.seek(0)
                if 'DSA' in key_head:
                    keytype=paramiko.DSSKey
                elif 'RSA' in key_head:
                    keytype=paramiko.RSAKey
                else:
                    raise Exception("Can't identify key type")
                pkey=keytype.from_private_key(key_file)
                self.t.auth_publickey(username, pkey)
            else:
                if password is not None:
                    self.t.auth_password(username,password,fallback=False)
                else: raise Exception('Must supply either key_file or password')
            self.sftp=paramiko.SFTPClient.from_transport(self.t)
    
        def command(self,cmd):
            #  Breaks the command by lines, sends and receives 
            #  each line and its output separately
            #
            #  Returns the server response text as a string
    
            chan = self.t.open_session()
            chan.get_pty()
            chan.invoke_shell()
            chan.settimeout(20.0)
            ret=''
            try:
                ret+=chan.recv(1024)
            except:
                chan.send('\n')
                ret+=chan.recv(1024)
            for line in cmd.split('\n'):
                chan.send(line.strip() + '\n')
                ret+=chan.recv(1024)
            return ret
    
        def put(self,localfile,remotefile):
            #  Copy localfile to remotefile, overwriting or creating as needed.
            self.sftp.put(localfile,remotefile)
    
        def put_all(self,localpath,remotepath):
            #  recursively upload a full directory
            os.chdir(os.path.split(localpath)[0])
            parent=os.path.split(localpath)[1]
            for walker in os.walk(parent):
                try:
                    self.sftp.mkdir(os.path.join(remotepath,walker[0]))
                except:
                    pass
                for file in walker[2]:
                    self.put(os.path.join(walker[0],file),os.path.join(remotepath,walker[0],file))
    
        def get(self,remotefile,localfile):
            #  Copy remotefile to localfile, overwriting or creating as needed.
            self.sftp.get(remotefile,localfile)
    
        def sftp_walk(self,remotepath):
            # Kindof a stripped down  version of os.walk, implemented for 
            # sftp.  Tried running it flat without the yields, but it really
            # chokes on big directories.
            path=remotepath
            files=[]
            folders=[]
            for f in self.sftp.listdir_attr(remotepath):
                if S_ISDIR(f.st_mode):
                    folders.append(f.filename)
                else:
                    files.append(f.filename)
            print (path,folders,files)
            yield path,folders,files
            for folder in folders:
                new_path=os.path.join(remotepath,folder)
                for x in self.sftp_walk(new_path):
                    yield x
    
        def get_all(self,remotepath,localpath):
            #  recursively download a full directory
            #  Harder than it sounded at first, since paramiko won't walk
            #
            # For the record, something like this would gennerally be faster:
            # ssh user@host 'tar -cz /source/folder' | tar -xz
    
            self.sftp.chdir(os.path.split(remotepath)[0])
            parent=os.path.split(remotepath)[1]
            try:
                os.mkdir(localpath)
            except:
                pass
            for walker in self.sftp_walk(parent):
                try:
                    os.mkdir(os.path.join(localpath,walker[0]))
                except:
                    pass
                for file in walker[2]:
                    self.get(os.path.join(walker[0],file),os.path.join(localpath,walker[0],file))
        def write_command(self,text,remotefile):
            #  Writes text to remotefile, and makes remotefile executable.
            #  This is perhaps a bit niche, but I was thinking I needed it.
            #  For the record, I was incorrect.
            self.sftp.open(remotefile,'w').write(text)
            self.sftp.chmod(remotefile,755)
    


知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看