pyguides

ftplib module

Overview

ftplib is Python’s standard library for interacting with FTP (File Transfer Protocol) servers. It handles the FTP protocol’s command-response pattern, letting you connect to servers, navigate directory trees, upload and download files, and manage passive/active modes. For most modern use cases involving file transfers, you might reach for paramiko (SFTP/SCP) or cloud storage SDKs instead — but for plain anonymous or credential-based FTP, ftplib gets the job done without extra dependencies.

Connection

Basic anonymous connection

from ftplib import FTP

ftp = FTP("ftp.example.com")
ftp.login()  # anonymous login with empty user/pass
print(ftp.getwelcome())

Connecting with credentials

from ftplib import FTP

ftp = FTP("ftp.example.com")
ftp.login(user="alice", passwd="secret123")
# or:
ftp.connect("ftp.example.com", 21)
ftp.login(user="alice", passwd="secret123")

Context manager (Python 3.2+)

from ftplib import FTP

with FTP("ftp.example.com") as ftp:
    ftp.login(user="alice", passwd="secret123")
    print(ftp.pwd())
# Connection closes automatically

Using TLS (FTPS)

from ftplib import FTP_TLS

with FTP_TLS("ftp.example.com") as ftp:
    ftp.login(user="alice", passwd="secret123")
    ftp.prot_p()  # switch to protected data channel
    print(ftp.pwd())
ftp.pwd()                # current directory
ftp.cwd("/pub/incoming")  # change directory
ftp.retrlines("LIST")    # list files as text
ftp.dir()                # same as retrlines("LIST")

Listing files

# Simple listing
ftp.retrlines("LIST")

# Detailed listing
ftp.retrlines("LIST -la")

# Use nlst for just filenames
files = ftp.nlst()
print(files)  # ['file1.txt', 'subdir', 'report.pdf']

Downloading Files

Text mode (retrlines)

from ftplib import FTP

with FTP("ftp.example.com") as ftp:
    ftp.login()
    ftp.cwd("/pub/docs")

    # Read into a list of strings
    lines = []
    ftp.retrlines("RETR readme.txt", lines.append)
    print("\n".join(lines))

Binary mode (retrbinary)

with FTP("ftp.example.com") as ftp:
    ftp.login()
    ftp.cwd("/pub/images")

    with open("photo.jpg", "wb") as f:
        ftp.retrbinary("RETR photo.jpg", f.write)

Download with progress tracking

def track_progress(data, f):
    f.write(data)
    print(".", end="", flush=True)

with FTP("ftp.example.com") as ftp:
    ftp.login()
    with open("largefile.zip", "wb") as f:
        ftp.retrbinary("RETR largefile.zip", lambda d: track_progress(d, f))

Uploading Files

Binary upload (storbinary)

with FTP("ftp.example.com") as ftp:
    ftp.login()
    ftp.cwd("/pub/incoming")

    with open("upload.txt", "rb") as f:
        ftp.storbinary("STOR upload.txt", f)

Text upload (storlines)

lines = ["First line", "Second line", "Third line"]

with FTP("ftp.example.com") as ftp:
    ftp.login()
    ftp.cwd("/pub/incoming")

    ftp.storlines("STOR notes.txt", lines)

Upload from a file object

with open("data.csv", "rb") as f:
    with FTP("ftp.example.com") as ftp:
        ftp.login()
        ftp.storbinary("STOR data.csv", f)

Renaming and Deleting

ftp.rename("old_name.txt", "new_name.txt")  # rename
ftp.delete("unwanted.txt")                   # delete file
ftp.mkd("/new_directory")                   # create directory
ftp.rmd("/empty_directory")                  # remove empty directory

Transfer Mode

FTP has two transfer modes that matter in ftplib:

Passive mode — The client tells the server which port to use for data transfer. This is the default in Python’s ftplib and works better through firewalls and NAT:

ftp = FTP("ftp.example.com")
ftp.login()
ftp.set_pasv(True)  # explicitly enable passive (default)

Active mode — The server opens a connection back to the client. This can fail behind firewalls or NAT:

ftp.set_pasv(False)  # disable passive = active mode

Error Handling

from ftplib import FTP, FTP_TLS, all_errors
import ftplib

try:
    with FTP("ftp.example.com", timeout=10) as ftp:
        ftp.login(user="alice", passwd="secret123")
        files = ftp.nlst()
except ftplib.error_perm as e:
    print(f"Permission error: {e}")
except ftplib.error_temp as e:
    print(f"Temporary error (retry): {e}")
except ftplib.all_errors as e:
    print(f"FTP error: {e}")

Common exceptions:

  • error_perm — 4xx errors (authentication failed, file not found)
  • error_temp — 4xx transient errors (try again)
  • error_proto — protocol-level errors

Downloading a File List with a Timeout

import ftplib

def fetch_filelist(ftp, dir_path):
    ftp.cwd(dir_path)
    files = []
    ftp.retrlines("LIST", files.append)
    return files

with FTP("ftp.example.com", timeout=30) as ftp:
    ftp.login()
    try:
        file_list = fetch_filelist(ftp, "/pub")
        for line in file_list:
            print(line)
    except ftplib.error_temp:
        print("Server busy, try again later")

See Also