# Python FTP 教程

> 原文： [http://zetcode.com/python/ftp/](http://zetcode.com/python/ftp/)

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 代码需要稍微不同的方法。

```py
import ftplib 

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

```

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

```py
import ftplib 
from contextlib import closing

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

```

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

## 欢迎消息

`getwelcome()`返回服务器为响应初始连接而发送的欢迎消息。 该消息可能包含一些对用户有用的信息。

`welcome.py`

```py
#!/usr/bin/python3

import ftplib

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

```

该示例创建与 Debian FTP 服务器的连接，该服务器具有一个匿名帐户并返回其欢迎消息。

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

```

这是程序的输出。

## 目录列表

`dir()`方法产生一个目录列表。

`listing.py`

```py
#!/usr/bin/python3

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`主机，并检索初始登录目录的目录列表。

```py
try:
    ftp.login()  

```

当`login()`方法没有参数时； 我们连接到 FTP 站点的匿名帐户。

```py
files = []

ftp.dir(files.append)

```

`dir()`方法产生目录列表，并将数据添加到列表中。

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

```

这是输出。

## FTP 命令

FTP 客户端将命令发送到 FTP 服务器，例如`PWD`或`RETR`。 `ftplib`包含几种包装这些命令的方法。 使用`sendcmd()`或`voidcmd()`方法发送命令。

`ftp_commands.py`

```py
#!/usr/bin/python3

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()`方法来检索当前工作目录。

```py
wdir = ftp.sendcmd('PWD')

```

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

```py
print(ftplib.parse257(wdir))

```

`parse257()`是一个帮助程序方法，它从返回的字符串中检索目录，该字符串还包含状态代码。

```py
wdir2 = ftp.pwd()
print(wdir2)

```

在这里，我们使用`pwd()`方法检索当前工作目录。

```py
$ ./ftp_commands.py 
/
/

```

这是输出。

## 变更目录

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

`change_directory.py`

```py
#!/usr/bin/python3

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`文件夹。

```py
$ ./change_directory.py 
/
/debian

```

这是输出。

## 创建目录

使用`mkd()`方法创建目录。 此操作需要具有足够特权的用户帐户； 它不适用于匿名帐户。

`create_directory.py`

```py
#!/usr/bin/python3

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 服务器，并在登录文件夹中创建一个新目录。

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

```

我们使用`login()`方法登录。

```py
ftp.mkd('newdir') 

```

使用`mkd()`方法创建一个新目录。

```py
files = []

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

```

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

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

```

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

## 获取文本文件的大小

`SIZE`命令及其等效的`size()`方法是确定文件大小的非标准方法。 尽管没有标准化，但是它由许多服务器实现。

`text_file_size.py`

```py
#!/usr/bin/python3

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`

```py
#!/usr/bin/python3

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) 

```

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

```py
ftp.sendcmd('TYPE I') 

```

我们使用`TYPE I`命令进入二进制模式。

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

```

我们得到一个二进制文件的大小。

## 下载文本文件

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

`download_text_file.py`

```py
#!/usr/bin/python3

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`服务器下载文本文件。

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

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

```

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

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

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

```

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

## 上传文本文件

具有`storlines()`方法的`STOR`命令用于上传文本文件。

`upload_text_file.py`

```py
#!/usr/bin/python3

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 `ftplib`。

您可能也对以下相关教程感兴趣： [Python 教程](/lang/python/)， [Python 集教程](/python/set/)， [Python lambda 函数](/python/lambda/)， [Python 列表推导](/articles/pythonlistcomprehensions/)， [Python 映射教程](/python/map/)， [OpenPyXL 教程](/articles/openpyxl/)， [Python Requests 教程](/web/pythonrequests/)和 [Python CSV 教程](/python/csv/)。