This post shows how to use the Python library Paramiko to implement a SFTP client that can be used to programatically send and receive files over SFTP. As when using Paramiko for SSH communication, authentication is performed using either username and password or username and a private key.
Preparations
The preparations are identical to those described in my previous post on SSH communication using Paramiko, please refer to that post for details.
Code
I have written two functions that both create a SFTPClient object connected to a computer on which remote file operations can be performed. The two functions differ slightly in that the first one uses a Paramiko Transport object to establish a connection to the (remote) computer and then create the SFTClient object using the Transport object. The second function, on the other hand, creates a Paramiko SSHClient object which is then used to open a SFTP connection and obtain a SFTPClient object.
import paramiko def create_sftp_client(host, port, username, password, keyfilepath, keyfiletype): """ create_sftp_client(host, port, username, password, keyfilepath, keyfiletype) -> SFTPClient Creates a SFTP client connected to the supplied host on the supplied port authenticating as the user with supplied username and supplied password or with the private key in a file with the supplied path. If a private key is used for authentication, the type of the keyfile needs to be specified as DSA or RSA. :rtype: SFTPClient object. """ sftp = None key = None transport = None try: if keyfilepath is not None: # Get private key used to authenticate user. if keyfiletype == 'DSA': # The private key is a DSA type key. key = paramiko.DSSKey.from_private_key_file(keyfilepath) else: # The private key is a RSA type key. key = paramiko.RSAKey.from_private_key(keyfilepath) # Create Transport object using supplied method of authentication. transport = paramiko.Transport((host, port)) transport.connect(None, username, password, key) sftp = paramiko.SFTPClient.from_transport(transport) return sftp except Exception as e: print('An error occurred creating SFTP client: %s: %s' % (e.__class__, e)) if sftp is not None: sftp.close() if transport is not None: transport.close() pass def create_sftp_client2(host, port, username, password, keyfilepath, keyfiletype): """ create_sftp_client(host, port, username, password, keyfilepath, keyfiletype) -> SFTPClient Creates a SFTP client connected to the supplied host on the supplied port authenticating as the user with supplied username and supplied password or with the private key in a file with the supplied path. If a private key is used for authentication, the type of the keyfile needs to be specified as DSA or RSA. :rtype: SFTPClient object. """ ssh = None sftp = None key = None try: if keyfilepath is not None: # Get private key used to authenticate user. if keyfiletype == 'DSA': # The private key is a DSA type key. key = paramiko.DSSKey.from_private_key_file(keyfilepath) else: # The private key is a RSA type key. key = paramiko.RSAKey.from_private_key(keyfilepath) # Connect SSH client accepting all host keys. ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh.connect(host, port, username, password, key) # Using the SSH client, create a SFTP client. sftp = ssh.open_sftp() # Keep a reference to the SSH client in the SFTP client as to prevent the former from # being garbage collected and the connection from being closed. sftp.sshclient = ssh return sftp except Exception as e: print('An error occurred creating SFTP client: %s: %s' % (e.__class__, e)) if sftp is not None: sftp.close() if ssh is not None: ssh.close() pass host = 'localhost' port = 22 username = 'ivan' keyfile_path = None password = 'secretpassword' sftpclient = create_sftp_client(host, port, username, password, keyfile_path, 'DSA') # List files in the default directory on the remote computer. dirlist = sftpclient.listdir('.') for row in dirlist: print row # Retrieve a file with the name 'remote_file.txt' on the remote computer and store it in a file named 'downloaded_file.txt' # next to this SFT client program. sftpclient.get('remote_file.txt', 'downloaded_file.txt') # Upload a file that locally has the name 'testfile.txt' to a file on the remote computer that will have the name 'remote_testfile.txt'. sftpclient.put('testfile.txt', 'remote_testfile.txt') # We're done with the SFTPClient. sftpclient.close()
The code above establishes a SFTP connection to the same computer on which it executes (localhost) on port 22 using the user-name “ivan” and the password “secretpassword” and then retrieves the directory listing of the current directory, downloads a file and uploads a file.
If you want to use a private key for authorization, set the variable keyfile_path to contain the absolute or relative path to a file containing the private key. Don’t forget to change the keyfile type from ‘DSA’ to ‘RSA’ if your private key is a RSA key.
If you now run the program, a directory listing should be printed to the console, a new file named ‘downloaded_file’ should appear and, in the remote directory, a file named ‘remote_testfile.txt’ should appear.
Happy coding!
Hi,
Is one function better than the other ? If yes, how ?
Thank you.
Thanks very much for the guide, however I get the following errors – desperate to get this working, all I had done was supplied host, username, keyfile path and password for paramters at the bottom and also changed DSA to RSA:
Traceback (most recent call last):
An error occurred creating SFTP client: : ‘str’ object has no attribute ‘readlines’
File “C:/Users/uc/PycharmProjects/WMDaten/SFTP.py”, line 94, in
dirlist = sftpclient.listdir(‘.’)
AttributeError: ‘NoneType’ object has no attribute ‘listdir’
Please help, Thanks you
Line 23 should be:
key = paramiko.RSAKey.from_private_key_file(keyfilepath) , that’s why RSA keys don’t work, just a typo.
thank you so much Ivan! I was having endless problems with paramiko and it was all my fault – if only I found your example 2 weeks ago I would have created the transport correctly
Help! Trying to execute the above example but keep getting the same error I cannot clear.
I picked up on the typo below but still not executing.
It appears to not be able to create the transport object.
Thanks, Jim
host = ‘1.3.2.4’
port = 22
username = ‘root’
password = ‘secret’
keyfile_path = None
C:\Users\james.dunn\PycharmProjects\RemoteCollector\venv\Scripts\python.exe C:/Users/james.dunn/PycharmProjects/RemoteCollector/main.py
An error occurred creating SFTP client: : EOF during negotiation
Traceback (most recent call last):
File “C:\Users\james.dunn\PycharmProjects\RemoteCollector\main.py”, line 98, in
dirlist = sftpclient.listdir(“/mnt/mmcblk0p1/”)
AttributeError: ‘NoneType’ object has no attribute ‘listdir’
Process finished with exit code 1