Transferts de répertoires sur paramiko

comment utiliser paramiko pour transférer des répertoires complets? Je suis en train d'utiliser:

sftp.put("/Folder1","/Folder2")

ce qui me donne cette erreur

Error : [Errno 21] Is a directory
19
demandé sur fixxxer 2010-12-10 17:00:38

8 réponses

Vous aurez besoin de faire cela, comme vous le feriez localement avec python (si vous n'utilisiez pas shutils).

combinez os.walk()sftp.mkdir() et sftp.put(). Vous pouvez également vérifier chaque fichier et répertoire avec os.path.islink() selon que vous souhaitez résoudre des liens symboliques ou non.

4
répondu JimB 2010-12-10 16:32:39

Vous pouvez classer paramiko.SFTPClient et ajoutez la méthode suivante:

import paramiko
import os

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
11
répondu skoll 2013-11-26 08:48:53

vous pourriez remplacer sftp = self.client.open_sftp() avec celui de paramiko et se débarrasser de libcloud ici.

import os.path
from stat import S_ISDIR
from libcloud.compute.ssh import SSHClient
from paramiko.sftp import SFTPError

class CloudSSHClient(SSHClient):


    @staticmethod
    def normalize_dirpath(dirpath):
        while dirpath.endswith("/"):
            dirpath = dirpath[:-1]
        return dirpath


    def mkdir(self, sftp, remotepath, mode=0777, intermediate=False):
        remotepath = self.normalize_dirpath(remotepath)
        if intermediate:
            try:
                sftp.mkdir(remotepath, mode=mode)
            except IOError, e:
                self.mkdir(sftp, remotepath.rsplit("/", 1)[0], mode=mode,
                           intermediate=True)
                return sftp.mkdir(remotepath, mode=mode)
        else:
            sftp.mkdir(remotepath, mode=mode)


    def put_dir_recursively(self,  localpath, remotepath, preserve_perm=True):
        "upload local directory to remote recursively"

        assert remotepath.startswith("/"), "%s must be absolute path" % remotepath

        # normalize
        localpath = self.normalize_dirpath(localpath)
        remotepath = self.normalize_dirpath(remotepath)

        sftp = self.client.open_sftp()

        try:
            sftp.chdir(remotepath)
            localsuffix = localpath.rsplit("/", 1)[1]
            remotesuffix = remotepath.rsplit("/", 1)[1]
            if localsuffix != remotesuffix:
                remotepath = os.path.join(remotepath, localsuffix)
        except IOError, e:
            pass

        for root, dirs, fls in os.walk(localpath):
            prefix = os.path.commonprefix([localpath, root])
            suffix = root.split(prefix, 1)[1]
            if suffix.startswith("/"):
                suffix = suffix[1:]

            remroot = os.path.join(remotepath, suffix)

            try:
                sftp.chdir(remroot)
            except IOError, e:
                if preserve_perm:
                    mode = os.stat(root).st_mode & 0777
                else:
                    mode = 0777
                self.mkdir(sftp, remroot, mode=mode, intermediate=True)
                sftp.chdir(remroot)

            for f in fls:
                remfile = os.path.join(remroot, f)
                localfile = os.path.join(root, f)
                sftp.put(localfile, remfile)
                if preserve_perm:
                    sftp.chmod(remfile, os.stat(localfile).st_mode & 0777)
3
répondu Andrey Gerzhov 2012-05-16 08:02:55

Voici mon morceau de code:

import errno
import os
import stat

def download_files(sftp_client, remote_dir, local_dir):
    if not exists_remote(sftp_client, remote_dir):
        return

    if not os.path.exists(local_dir):
        os.mkdir(local_dir)

    for filename in sftp_client.listdir(remote_dir):
        if stat.S_ISDIR(sftp_client.stat(remote_dir + filename).st_mode):
            # uses '/' path delimiter for remote server
            download_files(sftp_client, remote_dir + filename + '/', os.path.join(local_dir, filename))
        else:
            if not os.path.isfile(os.path.join(local_dir, filename)):
                sftp_client.get(remote_dir + filename, os.path.join(local_dir, filename))


def exists_remote(sftp_client, path):
    try:
        sftp_client.stat(path)
    except IOError, e:
        if e.errno == errno.ENOENT:
            return False
        raise
    else:
        return True
3
répondu Alexandr Nikitin 2018-09-07 00:49:53

je ne pense pas que vous pouvez le faire. Consultez la documentation pour os.walk et copier chaque fichier "manuellement".

2
répondu Martijn 2010-12-10 14:14:00

fonctionne pour moi faire quelque chose comme ça, tous les dossiers et les fichiers sont copiés sur le serveur distant.

parent = os.path.expanduser("~")
for dirpath, dirnames, filenames in os.walk(parent):
    remote_path = os.path.join(remote_location, dirpath[len(parent)+1:])
        try:
            ftp.listdir(remote_path)
        except IOError:
            ftp.mkdir(remote_path)

        for filename in filenames:
            ftp.put(os.path.join(dirpath, filename), os.path.join(remote_path, filename))
2
répondu Zaffalon 2015-11-29 03:50:06
récursive de téléchargement de fichiers. Cependant, j'ai trouvé un solution récursive de charger à l'aide de Paramiko ici. Suit un extrait de leur fonction de téléchargement récursif:

   def _send_recursive(self, files):
        for base in files:
            lastdir = base
            for root, dirs, fls in os.walk(base):
                # pop back out to the next dir in the walk
                while lastdir != os.path.commonprefix([lastdir, root]):
                    self._send_popd()
                    lastdir = os.path.split(lastdir)[0]
                self._send_pushd(root)
                lastdir = root
                self._send_files([os.path.join(root, f) for f in fls])

vous pouvez essayer d'utiliser leur fonction SCPClient.put invoquer la fonction ci-dessus pour le téléchargement récursif ou l'implémenter par vous-même.

0
répondu Martin Kosek 2010-12-10 14:28:16

c'est ma première réponse StackOverflow. J'ai eu une tâche, aujourd'hui, qui est semblable à cela. Donc, j'ai essayé de trouver un moyen direct de copier un dossier entier de windows à linux en utilisant python et paramiko. Après un peu de recherche, j'ai trouvé cette solution qui fonctionne pour les dossiers de plus petite taille avec des sous-dossiers et des fichiers dans elle.

Cette solution fait d'abord le fichier zip pour le dossier courant (os.walk () est très utile ici), puis copie vers le serveur de destination et décompresse y.

zipHere = zipfile.ZipFile("file_to_copy.zip", "w")

for root, folders, files in os.walk(FILE_TO_COPY_PATH):
    for file in files:
        zipHere.write(os.path.join(root, file), arcname=os.path.join(os.path.relpath(root, os.path.dirname(FILE_TO_COPY_PATH)), file))
    for folder in folders:
        zipHere.write(os.path.join(root, folder), arcname=os.path.join(os.path.relpath(root, os.path.dirname(FILE_TO_COPY_PATH)), folder))
zipHere.close()

# sftp is the paramiko.SFTPClient connection
sftp.put('local_zip_file_location','remote_zip_file_location')

# telnet_conn is the telnetlib.Telnet connection
telnet_conn.write('cd cd_to_zip_file_location')
telnet_conn.write('unzip -o file_to_copy.zip')
0
répondu Raj401 2017-08-11 06:03:01