Upload files using SFTP in Python, but create directories if path doesn't exist
SFTP supports the usual FTP commands (chdir, mkdir, etc...), so use those:
sftp = paramiko.SFTPClient.from_transport(transport)try: sftp.chdir(remote_path) # Test if remote_path existsexcept 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 casesftp.close()
To fully emulate mkdir -p
, you can work through remote_path recursively:
import os.pathdef 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 Truesftp = paramiko.SFTPClient.from_transport(transport)mkdir_p(sftp, remote_path) sftp.put(local_path, '.') # At this point, you are in remote_pathsftp.close()
Of course, if remote_path also contains a remote file name, then it needs to be split off, the directory being passed to mkdir_p and the filename used instead of '.' in sftp.put.
Something simpler and slightly more readable too
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_)
Had to do this today. Here is how I did it.
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)