example - Suba archivos usando SFTP en Python, pero cree directorios si la ruta no existe
sftp python (5)
Algo más simple y un poco más legible también
def mkdir_p(sftp, remote, is_dir=False):
"""
emulates mkdir_p if required.
sftp - is a valid sftp object
remote - remote path to create.
"""
dirs_ = []
if is_dir:
dir_ = remote
else:
dir_, basename = os.path.split(remote)
while len(dir_) > 1:
dirs_.append(dir_)
dir_, _ = os.path.split(dir_)
if len(dir_) == 1 and not dir_.startswith("/"):
dirs_.append(dir_) # For a remote path like y/x.txt
while len(dirs_):
dir_ = dirs_.pop()
try:
sftp.stat(dir_)
except:
print "making ... dir", dir_
sftp.mkdir(dir_)
Quiero cargar un archivo en un servidor remoto con Python. Me gustaría comprobar de antemano si la ruta remota realmente existe, y si no es así, crearla. En pseudocódigo:
if(remote_path not exist):
create_path(remote_path)
upload_file(local_file, remote_path)
Estaba pensando en ejecutar un comando en Paramiko para crear la ruta (por ejemplo, mkdir -p remote_path
). Se me ocurrió esto:
# I didn''t test this code
import paramiko, sys
ssh = paramiko.SSHClient()
ssh.connect(myhost, 22, myusername, mypassword)
ssh.exec_command(''mkdir -p '' + remote_path)
ssh.close
transport = paramiko.Transport((myhost, 22))
transport.connect(username = myusername, password = mypassword)
sftp = paramiko.SFTPClient.from_transport(transport)
sftp.put(local_path, remote_path)
sftp.close()
transport.close()
Pero esta solución no me suena bien, porque cierro la conexión y la vuelvo a abrir. Hay una mejor manera de hacerlo?
Paramiko contiene una función mkdir:
SFTP es compatible con los comandos FTP habituales (chdir, mkdir, etc ...), así que usa esos:
sftp = paramiko.SFTPClient.from_transport(transport)
try:
sftp.chdir(remote_path) # Test if remote_path exists
except IOError:
sftp.mkdir(remote_path) # Create remote_path
sftp.chdir(remote_path)
sftp.put(local_path, ''.'') # At this point, you are in remote_path in either case
sftp.close()
Para emular completamente mkdir -p
, puedes trabajar a través de remote_path recursivamente:
import os.path
def mkdir_p(sftp, remote_directory):
"""Change to this directory, recursively making new folders if needed.
Returns True if any folders were created."""
if remote_directory == ''/'':
# absolute path so change directory to root
sftp.chdir(''/'')
return
if remote_directory == '''':
# top-level relative directory must exist
return
try:
sftp.chdir(remote_directory) # sub-directory exists
except IOError:
dirname, basename = os.path.split(remote_directory.rstrip(''/''))
mkdir_p(sftp, dirname) # make parent directories
sftp.mkdir(basename) # sub-directory missing, so created it
sftp.chdir(basename)
return True
sftp = paramiko.SFTPClient.from_transport(transport)
mkdir_p(sftp, remote_path)
sftp.put(local_path, ''.'') # At this point, you are in remote_path
sftp.close()
Por supuesto, si remote_path también contiene un nombre de archivo remoto, entonces debe dividirse, el directorio se pasa a mkdir_p y el nombre de archivo usado en lugar de ''.'' en sftp.put.
Suponiendo que las operaciones de sftp son caras, me gustaría ir con:
def sftp_mkdir_p(sftp, remote_directory):
dirs_exist = remote_directory.split(''/'')
dirs_make = []
# find level where dir doesn''t exist
while len(dirs_exist) > 0:
try:
sftp.listdir(''/''.join(dirs_exist))
break
except IOError:
value = dirs_exist.pop()
if value == '''':
continue
dirs_make.append(value)
else:
return False
# ...and create dirs starting from that level
for mdir in dirs_make[::-1]:
dirs_exist.append(mdir)
sftp.mkdir(''/''.join(dirs_exist))```
Tenía que hacer esto hoy. Así es como lo hice.
def mkdir_p(sftp, remote_directory):
dir_path = str()
for dir_folder in remote_directory.split("/"):
if dir_folder == "":
continue
dir_path += r"/{0}".format(dir_folder)
try:
sftp.listdir(dir_path)
except IOError:
sftp.mkdir(dir_path)