How to Create SFTP Functionality in Python
-
Use
pysftp
to Create SFTP Functionality in Python -
Use
paramiko
to Create SFTP Functionality in Python
Secure Socket Shell (SSH) is a secure and better network protocol that allows us to access another computer and uses a password and public key authentication via SHA and encryption.
SSH File Transfer Protocol (SFTP) is a file transfer protocol that uses SSH and is better than the typical FTP that people previously used.
A file transfer protocol might be necessary for developing our application in Python. We should use the SFTP that gives us the default ability to overcome attacks such as password sniffing and man-in-the-middle and maintain our data integrity.
This article shows you how to use SFTP within your Python to move your data and files.
Use pysftp
to Create SFTP Functionality in Python
Python comes with ftplib
, an FTP client class with helper functions that provide the insecure FTP protocol service. For us to use SFTP, we need to install third-party libraries, and one of such libraries is the pysftp
library.
With pysftp
, you can access SFTP and work with the secure protocol to serve your application needs. To install pysftp
, you need to use pip
.
pip install pysftp
Also, we need an SFTP server. For Windows, we are going to use the WinSCP
software, and to learn how to set up an SFTP server client on your Windows PC, you can go through this installation guide. However, if you have an SFTP server, let’s get started.
Before we write some code, we will log in to our SFTP server using our private key
and the username
(akinl
) and hostname (localhost
).
Now, we are logged in to the root
folder. Our goal will be to list the files and directory present within the root
directory and copy files into the SFTP
server, especially the store
directory.
Let’s start coding using the pre-defined code template specified by the pysftp
library. Within the code, we have assigned our hostname
, port
, username
, and private key path
.
These values are informed from your SFTP server details, and the private key
is copied to the python file’s directory.
import pysftp
sftpHostName = "localhost"
sftpPort = 22
userName = "akinl"
privateKeyPath = "./id_rsa"
with pysftp.Connection(
host=sftpHostName,
port=sftpPort,
username=userName,
private_key=privateKeyPath,
cnopts=cnOptions,
) as sftp:
print("Connected to SFTP server!")
The above code connects to the SFTP server using an SFTP connection object (pysftp.Connection()
) with the specified parameters. Inside the with
block, we have an established SFTP connection within the object named sftp
.
Following is an output of the code:
C:\\Python310\\lib\\site-packages\\pysftp\\__init__.py:61: UserWarning: Failed to load HostKeys from C:\\Users\\akinl\\.ssh\\known_hosts. You will need to explicitly load HostKeys (cnopts.hostkeys.load(filename)) or disableHostKey checking (cnopts.hostkeys = None).
warnings.warn(wmsg, UserWarning)
Traceback (most recent call last):
File "c:\\Users\\akinl\\Documents\\Python\\SFTP\\index.py", line 8, in <module>
with pysftp.Connection(host=sftpHostName, port=sftpPort, username=userName, private_key=privateKeyPath) as sftp:
File "C:\\Python310\\lib\\site-packages\\pysftp\\__init__.py", line 132, in __init__
self._tconnect['hostkey'] = self._cnopts.get_hostkey(host)
File "C:\\Python310\\lib\\site-packages\\pysftp\\__init__.py", line 71, in get_hostkey
raise SSHException("No hostkey for host %s found." % host)
paramiko.ssh_exception.SSHException: No hostkey for host localhost found.
Exception ignored in: <function Connection.__del__ at 0x000001F0E9656320>
Traceback (most recent call last):
File "C:\\Python310\\lib\\site-packages\\pysftp\\__init__.py", line 1013, in __del__
self.close()
File "C:\\Python310\\lib\\site-packages\\pysftp\\__init__.py", line 784, in close
if self._sftp_live:
AttributeError: 'Connection' object has no attribute '_sftp_live'
No hostkey for host %s found
is a common error when working with SFTP connection objects with pysftp
, which happens when the host file is not present.
To handle the issue, we can create connection options (pysftp.CnOpts()
), specify that the host keys are None
, and ignore the known hosts check.
import pysftp
sftpHostName = "localhost"
sftpPort = 22
userName = "akinl"
privateKeyPath = "./id_rsa"
cnOptions = pysftp.CnOpts()
cnOptions.hostkeys = None
with pysftp.Connection(
host=sftpHostName,
port=sftpPort,
username=userName,
private_key=privateKeyPath,
cnopts=cnOptions,
) as sftp:
print("SFTP server connection successful")
The output of the code is as follows:
C:\Python310\lib\site-packages\pysftp\__init__.py:61: UserWarning: Failed to load HostKeys from C:\Users\akinl\.ssh\known_hosts. You will need to explicitly load HostKeys (cnopts.hostkeys.load(filename)) or disableHostKey checking (cnopts.hostkeys = None).
warnings.warn(wmsg, UserWarning)
SFTP server connection successful
The only error we have is a low-level warning about the disabled host key checking. First, let’s change the working directory to show you we are within the SFTP server.
import pysftp
sftpHostName = "localhost"
sftpPort = 22
userName = "akinl"
privateKeyPath = "./id_rsa"
cnOptions = pysftp.CnOpts()
cnOptions.hostkeys = None
with pysftp.Connection(
host=sftpHostName,
port=sftpPort,
username=userName,
private_key=privateKeyPath,
cnopts=cnOptions,
) as sftp:
print("SFTP server connection successful")
print("The current working directory is ", sftp.pwd)
sftp.cwd("./store")
print("After the cwd operation, the current working directory is ", sftp.pwd)
The above code’s output is given below:
SFTP server connection successful
The current working directory is /
After the cwd operation, the current working directory is /store.
The cwd
changes the current working directory to what’s specified as its argument. Also, we can list the files within the root
and store
directories using the listdir()
method and the files within the
import pysftp
sftpHostName = "localhost"
sftpPort = 22
userName = "akinl"
privateKeyPath = "./id_rsa"
cnOptions = pysftp.CnOpts()
cnOptions.hostkeys = None
with pysftp.Connection(
host=sftpHostName,
port=sftpPort,
username=userName,
private_key=privateKeyPath,
cnopts=cnOptions,
) as sftp:
rootFiles = sftp.listdir()
storeFiles = sftp.listdir("./store")
print(rootFiles, storeFiles)
The output of the code is as follows:
['index.txt', 'main.py', 'store'] []
The listdir()
method lists all the files and directories within the current working directory if no argument is passed, but if we give an argument, it checks for files within the argument we pass. The result was two files and one directory for the root
directory and none for the store
directory because no file exists.
Now, let’s move some files into our SFTP server using some methods, put()
, put_d()
, and put_r()
. We will use the put()
to move only files.
Next, create a text file named test.txt
within the same directory as our python file and copy the file into the SFTP server.
import pysftp
sftpHostName = "localhost"
sftpPort = 22
userName = "akinl"
privateKeyPath = "./id_rsa"
cnOptions = pysftp.CnOpts()
cnOptions.hostkeys = None
with pysftp.Connection(
host=sftpHostName,
port=sftpPort,
username=userName,
private_key=privateKeyPath,
cnopts=cnOptions,
) as sftp:
sftp.put("test.txt", preserve_mtime=True)
The output of the code:
The test.txt
file is now in the SFTP server root directory. Now, let’s move the same test.txt
to the store
directory and list its file content before and after copying it.
import pysftp
sftpHostName = "localhost"
sftpPort = 22
userName = "akinl"
privateKeyPath = "./id_rsa"
cnOptions = pysftp.CnOpts()
cnOptions.hostkeys = None
with pysftp.Connection(
host=sftpHostName,
port=sftpPort,
username=userName,
private_key=privateKeyPath,
cnopts=cnOptions,
) as sftp:
print(sftp.listdir("./store"))
sftp.put("test.txt", preserve_mtime=True, remotepath="./store/upload.txt")
print(sftp.listdir("./store"))
The above code’s output shows that the test.txt
file was uploaded to the server as upload.txt
and is visible within the image.
[]
['upload.txt']
We can copy a directory’s content using the put_d()
method. For example, let’s create a SeptData
directory containing three text files (one.txt
, two.txt
, and three.txt
) and copy the directory content to the root
folder.
However, for the path to copy from, we will need the full path, not the relative path we have used previously.
import pysftp
sftpHostName = "localhost"
sftpPort = 22
userName = "akinl"
privateKeyPath = "./id_rsa"
cnOptions = pysftp.CnOpts()
cnOptions.hostkeys = None
with pysftp.Connection(
host=sftpHostName,
port=sftpPort,
username=userName,
private_key=privateKeyPath,
cnopts=cnOptions,
) as sftp:
print(sftp.listdir("./"))
sftp.put_d(
r"C:\Users\akinl\Documents\Python\SFTP\SeptData", "./", preserve_mtime=True
)
print(sftp.listdir("./"))
The output of the code:
['index.txt', 'main.py', 'store', 'test.txt']
['index.txt', 'main.py', 'one.txt', 'store', 'test.txt', 'three.txt', 'two.txt']
The three files are now present within the root
directory, as represented by the list of files and directories within the directory. Therefore, we can download files from the SFTP server using the get()
method.
import pysftp
sftpHostName = "localhost"
sftpPort = 22
userName = "akinl"
privateKeyPath = "./id_rsa"
cnOptions = pysftp.CnOpts()
cnOptions.hostkeys = None
with pysftp.Connection(
host=sftpHostName,
port=sftpPort,
username=userName,
private_key=privateKeyPath,
cnopts=cnOptions,
) as sftp:
sftp.get("./store/upload.txt", preserve_mtime=True)
After successfully running the code, the upload.txt
file will be present within the directory of the python file. You can get remote directories using the get_d()
and get_r()
methods.
Use paramiko
to Create SFTP Functionality in Python
Paramiko is a great library that provides a straightforward implementation of SSHv2
for Python via its classes and methods. We can use some of these methods to initiate connections to an SFTP server and work with that server via public key
authentication.
To install paramiko
, you can use the pip
command as follows:
pip install paramiko
Using the connection details from the last section, we can carry out the same operations, from changing working directories to getting files from the remote SFTP server.
The SSHClient()
creates a new SSH for us to connect to the SFTP server, and the set_missing_host_key_policy()
allows us to set a policy for connecting to servers without a known host key, and the connect()
method creates the actual connection to the SFTP server.
Let’s change the directory to the store
directory and print the current working directory and the contents of the said directory with the help of chdir
, getcwd
, and listdir
, respectively.
import paramiko
sftpHostName = "localhost"
sftpPort = 22
userName = "akinl"
privateKeyPath = "./id_rsa"
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(
hostname=sftpHostName, port=sftpPort, username=userName, key_filename=privateKeyPath
)
sftp_client = ssh.open_sftp()
sftp_client.chdir("./store")
print(sftp_client.getcwd())
print(sftp_client.listdir())
sftp_client.close()
ssh.close()
The output of the code:
/store
['one.txt', 'three.txt', 'two.txt', 'upload.txt']
The first line contains the current working directory, which was set by the chdir()
method, and the second line holds a list of the files and directories within the store
directory.
Olorunfemi is a lover of technology and computers. In addition, I write technology and coding content for developers and hobbyists. When not working, I learn to design, among other things.
LinkedIn