2013-02-11 19 views
15

Voglio caricare un file su un server remoto con Python. Vorrei verificare in anticipo se il percorso remoto è realmente esistente e, in caso contrario, per crearlo. In pseudocodice:Carica file usando SFTP in Python, ma crea directory se il percorso non esiste

if(remote_path not exist): 
    create_path(remote_path) 
upload_file(local_file, remote_path) 

Stavo pensando di esecuzione di un comando in paramiko per creare il percorso (ad esempio mkdir -p remote_path). Sono arrivato fino a questo:

# 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() 

Ma questa soluzione non suona bene a me, perché io chiudo la connessione e quindi riaprirlo di nuovo. C'è un modo migliore per farlo?

+0

correlati: [os.renames per ftp in python] (http://stackoverflow.com/q/14641267/4279) – jfs

risposta

26

SFTP supporta i soliti comandi FTP (chdir, mkdir, ecc ...), in modo da utilizzare quelli:

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() 

Per emulare completamente mkdir -p, è possibile lavorare in modo remoto in modo ricorsivo:

Ovviamente, se percorso_remoto contiene anche un nome file remoto, è necessario separarlo, la directory viene passata a mkdir_p e il nome file utilizzato al posto di "." in sftp.put.

+0

non gestisce le directory padre non esistenti ('-p'). Confronta os.mkdir() vs os.makedirs(). Dividere il percorso ed effettuare la chiamata ricorsiva per creare le directory principali, se necessario – jfs

+0

sì, d'accordo, si aggiornerà di conseguenza. – isedev

+0

nella funzione mkdir_p non c'è un handle per sftp – franzlorenzon

5

qualcosa di più semplice e un po 'più leggibile troppo

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_) 
+0

+1 per fornire un'alternativa non ricorsiva. Si noti che il parametro di input "remoto" qui è un percorso file remoto.Se si desidera che questa funzione abbia un percorso di directory remoto come input, sostituire "dir_, basename = os.path.split (remote)" con "dir_ = remote". –

+0

@AlanEvangelista Grazie per il commento. Aggiornato il codice che passa un flag 'is_dir'. Si prega di rivedere e modificare se necessario. – gabhijit

1

dovuto farlo oggi. Ecco come l'ho fatto.

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)