ZetCode

Python FTP

最后修改于 2024 年 1 月 29 日

Python FTP 编程教程介绍了如何使用 ftplib 库在 Python 中处理 FTP。我们将连接到 FTP 服务器、列出目录、下载和上传文件。

FTP

文件传输协议 (FTP) 是一种标准的网络协议,用于在计算机网络上的客户端和服务器之间传输计算机文件。客户端和服务器使用一组 FTP 命令进行通信,例如 DELE、RETR 或 CWD。

许多服务器提供带匿名 FTP 访问的 FTP 服务;例如,有一些 Linux 托管站点提供匿名 FTP 帐户以下载发行版镜像。

Python ftplib

Python ftplib 是一个实现了 FTP 协议客户端的模块。它包含一个 FTP 客户端类和一些辅助函数。

Python FTP 类

ftplib.FTP 创建 FTP 类的新实例。当提供主机时,会使用 connect 方法连接到该主机。

上下文管理器

与 Python 3 不同,Python 2 没有在 FTP 类中实现上下文管理器。因此,Python 2 代码在处理连接对象时需要稍微不同的方法。

import ftplib

with ftplib.FTP('ftp.debian.org') as ftp:

对于 Python 3 代码,with 命令将自动关闭与服务器的连接。

import ftplib
from contextlib import closing

with closing(ftplib.FTP('ftp.debian.com')) as ftp:

对于 Python 2 代码,我们需要使用 contextlib 模块的 closing 方法。

欢迎消息

getwelcome 返回服务器在初始连接时发送的欢迎消息。此消息可能包含一些有用的用户信息。

welcome.py
#!/usr/bin/python

import ftplib

with ftplib.FTP('ftp.debian.org') as ftp:
    print(ftp.getwelcome())

该示例连接到 Debian FTP 服务器,该服务器具有匿名帐户并返回其欢迎消息。

$ ./welcome.py
220 ftp.debian.org FTP server

目录列表

dir 方法生成目录列表。

listing.py
#!/usr/bin/python

import ftplib

with ftplib.FTP('ftp.debian.org') as ftp:

    try:
        ftp.login()

        files = []

        ftp.dir(files.append)

        print(files)

    except ftplib.all_errors as e:
        print('FTP error:', e)

该示例连接到 ftp.debian.org 主机并检索初始登录目录的目录列表。

try:
    ftp.login()

login 方法没有参数时;我们连接到 FTP 站点的匿名帐户。

files = []

ftp.dir(files.append)

dir 方法生成目录列表并将数据添加到列表中。

$ ./listing.py
['drwxr-xr-x    9 1176     1176         4096 Sep 26 15:07 debian']

FTP 命令

FTP 客户端向 FTP 服务器发送命令,例如 PWDRETR。ftplib 包含包装这些命令的各种方法。命令使用 sendcmdvoidcmd 方法发送。

ftp_commands.py
#!/usr/bin/python

import ftplib

with ftplib.FTP('ftp.debian.org') as ftp:

    try:
        ftp.login()

        wdir = ftp.sendcmd('PWD')
        print(ftplib.parse257(wdir))

        wdir2 = ftp.pwd()
        print(wdir2)

    except ftplib.all_errors as e:
        print('FTP error:', e)

该示例通过直接发送 PWD 命令并使用 pwd 方法来检索当前工作目录。

wdir = ftp.sendcmd('PWD')

我们使用 sendcmd 方法发送 PWD 命令。

print(ftplib.parse257(wdir))

parse257 是一个辅助方法,用于从返回的字符串中检索目录,该字符串还包含状态码。

wdir2 = ftp.pwd()
print(wdir2)

这里我们使用 pwd 方法检索当前工作目录。

$ ./ftp_commands.py
/
/

更改目录

cwd 方法更改当前工作目录。

change_directory.py
#!/usr/bin/python

import ftplib

with ftplib.FTP('ftp.debian.org') as ftp:

    try:
        ftp.login()

        wdir = ftp.pwd()
        print(wdir)

        ftp.cwd('debian')

        wdir2 = ftp.pwd()
        print(wdir2)

    except ftplib.all_errors as e:
        print('FTP error:', e)

该示例使用 cmd 方法切换到 debian 文件夹。

$ ./change_directory.py
/
/debian

创建目录

使用 mkd 方法创建目录。此操作需要具有足够权限的用户帐户;匿名帐户不可用。

create_directory.py
#!/usr/bin/python

import ftplib
from contextlib import closing

with closing(ftplib.FTP('ftp.example.com')) as ftp:

    try:
        ftp.login('user7', 's$cret')

        ftp.mkd('newdir')

        files = []

        ftp.retrlines('LIST', files.append)

        for fl in files:
            print(fl)

    except ftplib.all_errors as e:
        print('FTP error:', e)

该示例连接到 FTP 服务器并在登录文件夹中创建一个新目录。

ftp.login('user7', 's$cret')

我们使用 login 方法登录。

ftp.mkd('newdir')

使用 mkd 方法创建新目录。

files = []

ftp.retrlines('LIST', files.append)

使用 LIST FTP 命令,我们检索文件列表和有关这些文件的信息。列表存储在 files 列表中。

$ ./create_directory.py
drwx------   6 example.com 117992          7 Sep 27 14:58 .
drwx------   6 example.com 117992          7 Sep 27 14:58 ..
-rw-------   1 example.com 117992        151 Jul 31  2015 .htaccess
drwxr-xr-x   2 0        0            4096 Sep 27 01:16 logs
drwx---r-x   2 example.com 117992          2 Sep 27 14:58 newdir
drwx------   3 example.com 117992          3 Mar 11  2011 sub
drwx------  26 example.com 117992         31 Sep 25 15:32 web

从输出中可以看到 newdir 已创建。

获取文本文件大小

SIZE 命令及其等效的 size 方法是确定文件大小的非标准方法。尽管尚未标准化,但许多服务器都实现了它。

text_file_size.py
#!/usr/bin/python

import ftplib

with ftplib.FTP('ftp.debian.org') as ftp:

    try:
        ftp.login()

        size = ftp.size('debian/README')
        print(size)

    except ftplib.all_errors as e:
        print('FTP error:', e)

该示例使用 size 方法检索 README 文件的大小。

获取二进制文件大小

要确定二进制文件的大小,我们必须切换到二进制模式。

binary_file_size.py
#!/usr/bin/python

import ftplib

with ftplib.FTP('ftp.debian.org') as ftp:

    try:
        ftp.login()

        # TYPE A for ASCII mode
        ftp.sendcmd('TYPE I')

        size = ftp.size('debian/ls-lR.gz')
        print(size)

    except ftplib.all_errors as e:
        print('FTP error:', e)

该示例确定二进制文件的大小。

ftp.sendcmd('TYPE I')

我们通过 TYPE I 命令进入二进制模式。

size = ftp.size('debian/ls-lR.gz')

我们获取二进制文件的大小。

下载文本文件

要下载文本文件,我们使用 RETR FTP 命令。

download_text_file.py
#!/usr/bin/python

import ftplib
import os

with ftplib.FTP('ftp.debian.org') as ftp:

    file_orig = '/debian/README'
    file_copy = 'README'

    try:
        ftp.login()

        with open(file_copy, 'w') as fp:

            res = ftp.retrlines('RETR ' + file_orig, fp.write)

            if not res.startswith('226 Transfer complete'):

                print('Download failed')
                if os.path.isfile(file_copy):
                    os.remove(file_copy)

    except ftplib.all_errors as e:
        print('FTP error:', e)

        if os.path.isfile(file_copy):
            os.remove(file_copy)

该示例从 ftp.debian.org 服务器下载文本文件。

with open(file_copy, 'w') as fp:

    res = ftp.retrlines('RETR ' + file_orig, fp.write)

我们获取文件并将其写入本地副本文件。

if not res.startswith('226 Transfer complete'):

    print('Download failed')
    if os.path.isfile(file_copy):
        os.remove(file_copy)

如果下载失败,我们会打印错误消息并删除本地文件。

上传文本文件

STOR 命令和 storlines 方法用于上传文本文件。

upload_text_file.py
#!/usr/bin/python

import ftplib

with ftplib.FTP('ftp.example.com') as ftp:

    filename = 'README'

    try:
        ftp.login('user7', 's$cret')

        with open(filename, 'rb') as fp:

            res = ftp.storlines("STOR " + filename, fp)

            if not res.startswith('226 Transfer complete'):

                print('Upload failed')

    except ftplib.all_errors as e:
        print('FTP error:', e)

在此示例中,我们将文本文件上传到 FTP 服务器。

来源

Python FTP 协议客户端 - 文档

在本文中,我们使用了 Python ftplib

作者

我叫 Jan Bodnar,我是一名充满热情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直在撰写编程文章。迄今为止,我已撰写了 1,400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出所有 Python 教程