在互联网发展的早期阶段,FTP(文件传输协议)一直是服务器之间、服务器与客户端之间交换文件的首选方式。直到今天,大量企业内部系统、网站维护后台、数据交换平台仍然依赖FTP。Python标准库中的ftplib正是为这种场景而生的——它完整实现了FTP协议的客户端功能,让你能够用几行代码完成上传、下载、重命名、删除、遍历目录等操作,全程无需安装任何第三方依赖。

在实际生活中,ftplib的应用无处不在:网站运维:用脚本自动备份远程服务器的网页根目录到本地;数据交换:与合作伙伴约定通过FTS(FTP共享)交换每日报表;嵌入式设备:智能摄像头将通过ftplib把拍摄的图片定时上传到FTP服务器;个人NAS:可以写一个同步脚本,将手机照片通过WIFI自动备份到家庭FTP存储。它的核心价值是简单、可靠、无外部依赖,特别适合编写自动化运维脚本、定时任务以及资源受限环境下的文件传输处理。

一、安装ftplib

由于ftplib是Python的内置标准库,所以同样不需要执行任何安装命令。只要Python环境正常,直接导入即可使用:

python

import ftplib
print(ftplib.__doc__)

二、基本用法——4步掌握FTP核心操作

以下步骤将演示如何连接、登录、上传和下载文件。

1. 连接FTP服务器并登录

python

from ftplib import FTP

# 创建FTP对象并连接(显式指定主机)
ftp = FTP('ftp.example.com')
# 或者先创建对象,再connect
# ftp = FTP()
# ftp.connect('ftp.example.com', 21)

# 登录(匿名登录可使用空用户名/密码,或者主动传入)
ftp.login(user='your_username', passwd='your_password')

# 若匿名登录:ftp.login()
print(ftp.getwelcome())  # 打印欢迎信息
2. 浏览服务器目录

python

# 列出当前目录下的文件和文件夹(返回列表)
files = ftp.nlst()
print("文件列表:", files)

# 更详细的列表(类似ls -l)
ftp.dir()

# 切换目录
ftp.cwd('/pub/files')
print("当前工作目录:", ftp.pwd())
3. 从FTP下载文件

python

# 下载二进制文件(图片、压缩包等)
filename = 'document.pdf'
with open(filename, 'wb') as local_file:
    ftp.retrbinary(f'RETR {filename}', local_file.write)
print(f"{filename} 下载完成")

# 下载文本文件(也可用retrlines逐行处理)
def callback(line):
    print(line)   # 这里可以写入本地文件
ftp.retrlines('RETR readme.txt', callback)
4. 上传文件到FTP

python

# 上传二进制文件
local_file = 'report.xlsx'
with open(local_file, 'rb') as f:
    ftp.storbinary(f'STOR {local_file}', f)
print(f"{local_file} 上传成功")

# 上传文本文件(需以二进制模式打开,因为storbinary要求bytes)
with open('notes.txt', 'rb') as f:
    ftp.storbinary('STOR notes.txt', f)

三、高级用法——生产环境的必备技巧

1. 设置被动模式与超时

大多数FTP服务器使用被动模式(PASV),设置超时避免网络卡死。

python

ftp = FTP('ftp.example.com')
ftp.login('user', 'pass')
ftp.set_pasv(True)      # 启用被动模式(默认为True)
ftp.sock.settimeout(30) # 设置套接字超时30秒
2. 递归下载整个目录

FTP协议没有递归下载命令,需要自己实现遍历与文件夹判断。

python

import os
from ftplib import FTP

def download_dir(ftp, remote_dir, local_dir):
    if not os.path.exists(local_dir):
        os.makedirs(local_dir)
    ftp.cwd(remote_dir)
    items = ftp.nlst()
    for item in items:
        try:
            # 尝试切换到子目录,如果成功则是目录
            ftp.cwd(item)
            download_dir(ftp, item, os.path.join(local_dir, item))
            ftp.cwd('..')
        except ftplib.error_perm:
            # 不是目录,是文件
            local_file_path = os.path.join(local_dir, item)
            with open(local_file_path, 'wb') as f:
                ftp.retrbinary(f'RETR {item}', f.write)
            print(f"下载: {item}")

# 使用示例
with FTP('ftp.example.com') as ftp:
    ftp.login()
    download_dir(ftp, '/backup', './local_backup')
3. 异常处理与重连机制

python

from ftplib import FTP, error_perm, error_temp, error_reply
import time

def robust_ftp_operation(host, user, passwd, func, retries=3):
    for i in range(retries):
        ftp = FTP(host)
        try:
            ftp.login(user, passwd)
            result = func(ftp)
            ftp.quit()
            return result
        except (error_temp, error_reply) as e:
            print(f"临时错误,重试中 ({i+1}/{retries}): {e}")
            time.sleep(5)
        except error_perm as e:
            print(f"永久错误,停止重试: {e}")
            raise
    raise Exception("超过最大重试次数")
4. 使用TLS/SSL加密(FTPS)

对于需要安全传输的场景,可以使用ftplib.FTP_TLS类。

python

from ftplib import FTP_TLS

ftp = FTP_TLS('ftp.example.com')
ftp.login('user', 'pass')
ftp.prot_p()          # 启用数据通道加密
ftp.retrbinary('RETR secret.txt', open('secret.txt', 'wb').write)
ftp.quit()

四、实际应用场景——三个日常可落地的深度案例

案例一:定时备份网站文件到本地(运维必备)

假设你的网站根目录在FTP服务器的/wwwroot下,每天深夜自动全量备份到本地磁盘,并按日期命名文件夹。

python

import ftplib
import os
import time
from datetime import datetime

def backup_website():
    remote_path = '/wwwroot'
    local_base = r'D:\website_backups'
    date_str = datetime.now().strftime('%Y%m%d_%H%M%S')
    local_dir = os.path.join(local_base, date_str)
    
    with ftplib.FTP('ftp.yourhost.com') as ftp:
        ftp.login('backup_user', 'strong_password')
        ftp.cwd(remote_path)
        os.makedirs(local_dir, exist_ok=True)
        
        # 递归下载函数(复用上面的download_dir)
        download_dir(ftp, '.', local_dir)
    
    print(f"备份完成,保存至 {local_dir}")
    # 可添加删除7天前的备份逻辑

if __name__ == '__main__':
    backup_website()
案例二:监控FTP服务器上的新文件,自动处理(日志聚合)

很多设备(如路由器、摄像头)会将日志推送到FTP。你的脚本可以每隔几分钟扫描指定目录,发现新增文件就下载并进行处理(例如提取错误行并发送邮件)。

python

import ftplib
import time
import hashlib

def monitor_ftp_folder(host, user, passwd, remote_folder, check_interval=60):
    previous_hashes = {}
    with ftplib.FTP(host) as ftp:
        ftp.login(user, passwd)
        ftp.cwd(remote_folder)
        while True:
            current_files = {}
            for filename in ftp.nlst():
                # 获取文件大小和修改时间(需要MLSD命令支持,否则用SIZE和MDTM)
                try:
                    size = ftp.size(filename)
                    mtime = ftp.voidcmd(f'MDTM {filename}')[4:].strip()
                    current_files[filename] = (size, mtime)
                except:
                    pass
            # 新文件:不在previous_hashes中的
            new_files = set(current_files.keys()) - set(previous_hashes.keys())
            for fname in new_files:
                print(f"发现新文件: {fname}")
                local_path = f"./downloaded/{fname}"
                with open(local_path, 'wb') as f:
                    ftp.retrbinary(f'RETR {fname}', f.write)
                # 这里可添加自定义处理,比如解析日志
                with open(local_path, 'r', encoding='utf-8', errors='ignore') as lf:
                    if 'ERROR' in lf.read():
                        print(f"  -> 文件中发现错误日志,触发警报")
            previous_hashes = current_files
            time.sleep(check_interval)

monitor_ftp_folder('ftp.loghost.com', 'monitor', 'pass', '/logs', 120)
案例三:自动上传每日数据报表(数据管道)

假设你每天下午5点生成一个CSV销售报表,需要通过FTP发给供应商。可以配合定时任务(如cron)完成。

python

import ftplib
import os
from datetime import datetime

def upload_daily_report():
    report_file = f"sales_{datetime.now().strftime('%Y%m%d')}.csv"
    if not os.path.exists(report_file):
        print("报表尚未生成,退出")
        return
    with ftplib.FTP('ftp.supplier.com') as ftp:
        ftp.login('partner', 'shared_key')
        ftp.cwd('/incoming')
        with open(report_file, 'rb') as f:
            ftp.storbinary(f'STOR {report_file}', f)
        print(f"成功上传 {report_file} 到供应商FTP")
        # 可选:上传完成后移动本地文件到备份文件夹
        os.rename(report_file, f"uploaded_{report_file}")

if __name__ == '__main__':
    upload_daily_report()

五、结尾:总结与互动

ftplib这个看似“古老”的库,至今依然是Python处理FTP协议最直接、最稳定的方式。它不需要任何第三方依赖,API设计贴近原生FTP命令,让你能在几分钟内写出一段可靠的文件传输脚本。无论是想要搭建自己的云备份工具、自动化处理来自嵌入式设备的数据,还是对接仍然坚持用FTP的企业旧系统,ftplib都能成为你最得力的助手。

现在,轮到你了:你日常工作或生活中有哪些场景还在使用FTP?有没有试过用Python脚本来自动化处理这些重复性任务?如果你对ftplib.error_perm这类权限错误、中文文件名乱码、或者如何实现断点续传等进阶话题感兴趣,欢迎在评论区留言。我会挑选典型问题,后续专门出一篇“ftplib疑难杂症深度解析”。最后,强烈建议你亲自搭一个本地FTP服务器(比如用pyftpdlib),用本文的代码练练手,把文件传输的自动化能力真正掌握起来。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐