¿Cómo se usa paramiko para transferir directorios completos? Estoy tratando de utilizar:Transferencias de directorio en paramiko
sftp.put("/Folder1","/Folder2")
que me está dando este error -
Error : [Errno 21] Is a directory
¿Cómo se usa paramiko para transferir directorios completos? Estoy tratando de utilizar:Transferencias de directorio en paramiko
sftp.put("/Folder1","/Folder2")
que me está dando este error -
Error : [Errno 21] Is a directory
Tendrás que hacer esto como lo harías a nivel local con python (si no estuvieras usando shutils).
Combine os.walk()
, con sftp.mkdir()
y sftp.put()
. También es posible que desee comprobar cada archivo y directorio con dependiendo de si desea resolver enlaces simbólicos o no.
No creo que se puede hacer eso. Busque la documentación para os.walk
y copie cada archivo "manualmente".
Por lo que sé, Paramiko no admite la carga de archivo recursivo . Sin embargo, he encontrado un solution for recursive upload using Paramiko here. Sigue un extracto de su función de carga recursiva:
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])
Usted puede tratar de usar ya sea su función SCPClient.put
invocando la función anterior para la carga recursiva o implementar por su cuenta.
Puede reemplazar sftp = self.client.open_sftp()
con paramiko y deshacerse de libcloud
aquí.
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)
Respuesta bonita y completa. Solo algunos puntos menores: recomendaría usar 'os.path.split' en lugar de' str.rsplit'; también, defines un método 'normalize_path', pero luego haces' sufijo = sufijo [1:] 'en' put_dir_recursively'. –
Usted puede subclase paramiko.SFTPClient y añadir el siguiente método a la misma:
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
Obras para mí hacer algo como esto, todas las carpetas y los archivos se copian en el servidor remoto.
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))
Aquí es mi trozo de código:
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_file(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
Ésta es mi primera respuesta StackOverflow. Tuve una tarea hoy que es similar a esto. Entonces, traté de encontrar una forma directa de copiar toda la carpeta de Windows a Linux usando Python y Paramiko. Después de investigar un poco, se me ocurrió esta solución que funciona para carpetas de menor tamaño con subcarpetas y archivos.
Esta solución primero crea el archivo zip para la carpeta actual (os.walk() es muy útil aquí), luego lo copia al servidor de destino y descomprime allí.
os.walk() es la forma correcta de hacerlo, pero no copie esto exactamente, ya que maneja las cosas de una manera específica para SCP. SFTP funciona de manera un poco diferente (exención de responsabilidad, escribí ese código) – JimB
@Martin Kosek - Me gusta su respuesta, pero parece que su enlace a la solución está roto. ¿Podrías editar y arreglar? Gracias. – RobertMS
@RobertMS - a la derecha, veo que se eliminó el módulo de Python. En este caso, creo que la solución de JimB sería la mejor combinación de os.walk(), sftp.mkdir() y sftp.put() para lograr el objetivo. –