Introduction

In another article on using ftplib in Python, we talked about using Python’s ftplib library to connect to an FTP server and download both binary and text files to our local machine. In this segment, I’ll introduce several new concepts, including uploading text and binary files, error handling, and common directory commands using the same imported library.
.

Prerequisites

It is difficult to experiment with many of these calls with a server that you don’t own–most FTP servers will not allow anonymous logins. Assuming you do not have access to a web-based FTP server, your best bet is to install a server on your local machine (see “Installing an FTP server“) and test your code using localhost as the target server.
.

FTP Uploads

As with downloads, you’ll need to specify whether a file you wish to upload to a server is a text file or a binary file since each uses a different method. You can upload text files using the storlines() method and binary files with the storbinary() method. A nice feature of these functions is that neither one requires you to write a separate function to handle reading the source file: storlines() calls the readline() method on each line in the file until it reads the last line, while storbinary() uses the read() method until there is no more data to read and upload.

Once you have access to an FTP server, open a text editor and enter the following Python script:

from ftplib import FTP  
ftp = FTP('_your_server_address_')  
ftp.login('_username_', '_password_')  
with open('myfile.py', 'r') as f:  
    ftp.storbinary('STOR %s' % 'remotefile.py', f)  
ftp.quit()

This should have the effect of copying myfile.py from your local directory to the remote directory on your FTP server. Should you want to copy a text file instead, the script should look something like this:

from ftplib import FTP  
ftp = FTP('_your_server_address_')  
ftp.login('_username_', '_password_')  
with open('myfile.txt', 'r') as f:  
    ftp.storlines('STOR %s' % 'remotefile.txt', f)  
ftp.quit()

.

Working with Directories

Like any good FTP client, the ftplib library supports file deletion, renaming, moving, and even directory creation and deletion. These can be somewhat obscure calls since they’re not used very often, but they are very straightforward.

Like most library calls, you can experiment with these using an interactive Python prompt, rather than a complete, standalone script. To get a demonstration, connect to your FTP server:

>>> from ftplib import FTP  
>>> ftp = FTP('_your_server_address_')  
>>> ftp.login('_your_username_', '_your_password_')

Now you should be logged in, and you can experiment with some of the following library calls:

  • delete(_filename_) will delete a file from the server.
  • rename(_old filename_, _new filename_) will rename a file in the same directory, or move a file to a new directory, if you specify a new path in the second argument. For instance, rename ('spam.txt', 'eggs.txt') will rename the file spam.txt, but rename('spam.txt', 'new_directory/spam.txt') will move spam.txt into the new_directory within the present directory.
  • mkd(_directory_) will create a new directory.
  • rmd(_directory_) will attempt to remove a directory. Bear in mind that most FTP file servers require that a directory be empty (even of hidden files) before it can be deleted.

It is also possible to recursively “walk” through a directory, to go into all of the subdirectories and download (or print) all of the files you come across. Unfortunately, there is no elegant way to do this. The best way is to test whether each file you come across is a directory; if you can enter it, then you use the cwd(_directory name_) command to enter and test each file inside. You can use the nlist() command to return a list of all files in the current directory, and then try to enter each one.

We can probably best illustrate this behavior with a small script. In your text editor, enter the following:

# Thanks to _Foundations of Python Network Programming_  
# for the following code:  
import os  
import sys  
from ftplib import FTP  
def enter_dir(f, path):  
    original_dir = f.pwd()  
    try:  
        f.cwd(path)  
    except:  
        return  
    print path  
    names = f.nlst()  
    for name in names:  
        enter_dir(f, path + '/' + name)  
    f.cwd(original_dir)  
f = FTP('ftp.kernel.org')  
f.login()  
enter_dir(f, '/pub/linux/kernel/Historic/old-versions')  
f.quit()

This script recursively walks through the directories on the server, printing out all of the directory names it finds as it goes. If you’d like to test this code on your local server, simply substitute localhost for ftp.kernel.org and your home directory for /pub/linux/kernel/Historic/old-versions and run the code again. You’d also need to update f.login() to include your username and password as well, most likely. As long as the FTP server is running on your local machine, you should get a listing of subdirectories in your home directory.
.

Error Handling With the FTP library

Like most Python libraries and modules, ftplib will raise an exception if an error occurs during processing. It has a list of its own errors (ftplib.error_reply, for instance, when an unexpected error is received from the server), and it also raises the standard socket.error and IOError. If you’re used to using try/except clauses, ftplib will be second nature to you. If you’d like to see what error is generated, the following template could prove useful:

try:  
    ftp._some_Python_method_call_()
except ftplib.all_errors, e:  
    errorcode_string = str(e)  
    print errorcode_string

.

Conclusion

I hope these short introductions to Python’s ftplib library have shown how useful it can be. There are plenty more method calls available, and I highly recommend you check out the online Python documentation. Thank you for reading! Be sure to check back for more updates, and to learn more about our affordable cloud hosting solutions.
.
.