it-swarm.com.de

Laden Sie Dateien mit SFTP in Python hoch, erstellen Sie jedoch Verzeichnisse, wenn der Pfad nicht vorhanden ist

Ich möchte eine Datei mit Python auf einen Remote-Server hochladen. Ich möchte vorher prüfen, ob der entfernte Pfad wirklich vorhanden ist und wenn nicht, um ihn zu erstellen. Im Pseudocode:

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

Ich habe überlegt, einen Befehl in Paramiko auszuführen, um den Pfad zu erstellen (z. B. mkdir -p remote_path). Ich kam dazu:

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

Diese Lösung klingt aber nicht gut für mich, weil ich die Verbindung schließe und dann wieder öffne. Gibt es einen besseren Weg, dies zu tun?

20
franzlorenzon

SFTP unterstützt die üblichen FTP-Befehle (chdir, mkdir usw.), verwenden Sie also diese:

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

Um mkdir -p vollständig zu emulieren, können Sie remote_path rekursiv bearbeiten:

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

Wenn remote_path auch einen Remote-Dateinamen enthält, muss dieser natürlich getrennt werden. Das Verzeichnis wird an mkdir_p übergeben und der Dateiname wird anstelle von '.' in sftp.put.

36
isedev

Etwas einfacher und etwas lesbarer 

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_)
6
gabhijit

Musste das heute tun. So habe ich es gemacht.

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)
3
Mickey Afaneh
1
Benjamin

Angenommen, SFTP-Vorgänge sind teuer. Ich würde mit gehen:

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))```
0