
Python ftplib 库详解:基于最新版本的文件传输实战指南
- [一、Python ftplib库详解](#一、Python ftplib库详解)
-
- 1、引言
- 2、环境准备与基础概念
-
- [2.1 、环境要求](#2.1 、环境要求)
- [2.2、 FTP 协议简介](#2.2、 FTP 协议简介)
- [3、 ftplib 核心类与快速上手](#3、 ftplib 核心类与快速上手)
-
- [3.1 、核心类介绍](#3.1 、核心类介绍)
- [3.2 、快速连接示例](#3.2 、快速连接示例)
- 4、常用操作详解
-
- [4.1、 目录操作](#4.1、 目录操作)
- [4.2 、文件下载](#4.2 、文件下载)
- [4.3、 文件上传](#4.3、 文件上传)
- 5、高级特性
-
- [5.1 、使用 FTP_TLS 实现加密传输](#5.1 、使用 FTP_TLS 实现加密传输)
- [5.2 、断点续传](#5.2 、断点续传)
- [5.3、 目录递归遍历](#5.3、 目录递归遍历)
- [6、 异常处理与最佳实践](#6、 异常处理与最佳实践)
-
- [6.1 、异常处理](#6.1 、异常处理)
- [6.2 、使用上下文管理器](#6.2 、使用上下文管理器)
- [6.3、 最佳实践建议](#6.3、 最佳实践建议)
- 7、实际应用案例
-
- [7.1 、批量备份文件到 FTP 服务器](#7.1 、批量备份文件到 FTP 服务器)
- [7.2、 定时同步远程文件](#7.2、 定时同步远程文件)
- [8、 常见问题与解决方案](#8、 常见问题与解决方案)
-
- [8.1 、连接超时](#8.1 、连接超时)
- [8.2、 中文文件名乱码](#8.2、 中文文件名乱码)
- [8.3 、防火墙/NAT 环境下的连接问题](#8.3 、防火墙/NAT 环境下的连接问题)
- 9、总结
- 二、示例代码
一、Python ftplib库详解
1、引言
在互联网应用中,文件传输是一项基础且常见的需求。无论是将本地文件上传到服务器、从远程服务器下载数据,还是进行网站内容的日常维护,FTP(File Transfer Protocol,文件传输协议)都扮演着重要角色。Python 标准库中的 ftplib 模块,为我们提供了一套简洁而强大的 FTP 客户端实现,无需安装任何第三方依赖,即可轻松完成文件的上传、下载、目录浏览等操作。
2、环境准备与基础概念
2.1 、环境要求
- Python 3.8 及以上版本(推荐 3.12+)
- 一个可用的 FTP 服务器(本地或远程均可)
- 基本的网络知识
2.2、 FTP 协议简介
FTP 是一种基于 TCP 的应用层协议,默认使用 21 端口进行控制连接,20 端口进行数据传输。它支持两种工作模式:
- 主动模式(Active Mode):服务器主动连接客户端的数据端口
- 被动模式(Passive Mode):客户端主动连接服务器的数据端口(现代网络环境更常用)
ftplib 默认使用被动模式,这也是大多数现代 FTP 服务器的推荐配置。
3、 ftplib 核心类与快速上手
3.1 、核心类介绍
ftplib 模块主要提供以下几个核心类:
FTP:基础的 FTP 客户端类FTP_TLS:支持 TLS/SSL 加密的 FTP 客户端类(FTPS)FTP_HOST:FTP 主机信息类(Python 3.12+ 新增)error_perm、error_temp、error_proto:异常类
3.2 、快速连接示例
下面是一个最简单的连接示例:
python
from ftplib import FTP
# 连接 FTP 服务器
ftp = FTP('ftp.example.com')
# 登录(匿名登录)
ftp.login()
# 打印欢迎信息
print(ftp.getwelcome())
# 关闭连接
ftp.quit()
如果需要使用用户名和密码登录:
python
from ftplib import FTP
ftp = FTP('ftp.example.com')
ftp.login(user='username', passwd='password')
print(ftp.getwelcome())
ftp.quit()
4、常用操作详解
4.1、 目录操作
python
from ftplib import FTP
ftp = FTP('ftp.example.com')
ftp.login()
# 获取当前目录
current_dir = ftp.pwd()
print(f"当前目录: {current_dir}")
# 切换目录
ftp.cwd('/pub/files')
# 列出目录内容(详细列表)
ftp.retrlines('LIST')
# 列出目录内容(简化列表)
ftp.retrlines('NLST')
# 创建目录
ftp.mkd('/new_folder')
# 删除目录
ftp.rmd('/new_folder')
# 重命名文件或目录
ftp.rename('/old_name.txt', '/new_name.txt')
ftp.quit()
4.2 、文件下载
python
from ftplib import FTP
ftp = FTP('ftp.example.com')
ftp.login()
# 切换到目标目录
ftp.cwd('/pub/files')
# 下载文件到本地
with open('local_file.txt', 'wb') as local_file:
ftp.retrbinary('RETR remote_file.txt', local_file.write)
# 下载文本文件(文本模式)
with open('local_text.txt', 'w') as local_file:
ftp.retrlines('RETR remote_text.txt', local_file.write)
ftp.quit()
4.3、 文件上传
python
from ftplib import FTP
ftp = FTP('ftp.example.com')
ftp.login()
# 上传二进制文件
with open('local_file.zip', 'rb') as local_file:
ftp.storbinary('STOR remote_file.zip', local_file)
# 上传文本文件
with open('local_text.txt', 'r') as local_file:
ftp.storlines('STOR remote_text.txt', local_file)
ftp.quit()
5、高级特性
5.1 、使用 FTP_TLS 实现加密传输
python
from ftplib import FTP_TLS
# 创建 TLS 连接
ftps = FTP_TLS('ftp.example.com')
ftps.login(user='username', passwd='password')
# 启用数据通道加密
ftps.prot_p()
# 执行文件操作
ftps.retrlines('LIST')
# 上传文件
with open('local_file.txt', 'rb') as f:
ftps.storbinary('STOR remote_file.txt', f)
ftps.quit()
5.2 、断点续传
python
import os
from ftplib import FTP
def download_with_resume(ftp, remote_path, local_path):
"""支持断点续传的下载函数"""
# 检查本地文件大小
local_size = os.path.getsize(local_path) if os.path.exists(local_path) else 0
# 获取远程文件大小
remote_size = ftp.size(remote_path)
if local_size >= remote_size:
print("文件已完整下载,无需续传")
return
# 使用 REST 命令设置断点位置
ftp.voidcmd(f'TYPE I')
ftp.voidcmd(f'REST {local_size}')
with open(local_path, 'ab') as local_file:
ftp.retrbinary(f'RETR {remote_path}', local_file.write)
print(f"文件下载完成,共 {remote_size} 字节")
# 使用示例
ftp = FTP('ftp.example.com')
ftp.login()
download_with_resume(ftp, '/pub/files/big_file.zip', 'big_file.zip')
ftp.quit()
5.3、 目录递归遍历
python
from ftplib import FTP
def list_all_files(ftp, path='/'):
"""递归列出 FTP 服务器上的所有文件"""
files = []
try:
ftp.cwd(path)
items = ftp.nlst()
for item in items:
try:
# 尝试进入子目录
ftp.cwd(item)
files.extend(list_all_files(ftp, f"{path}/{item}"))
ftp.cwd('..')
except:
# 如果是文件,添加到列表
files.append(f"{path}/{item}")
except Exception as e:
print(f"访问 {path} 时出错: {e}")
return files
ftp = FTP('ftp.example.com')
ftp.login()
all_files = list_all_files(ftp)
for file in all_files:
print(file)
ftp.quit()
6、 异常处理与最佳实践
6.1 、异常处理
python
from ftplib import FTP, error_perm, error_temp, error_proto
try:
ftp = FTP('ftp.example.com', timeout=30)
ftp.login(user='username', passwd='password')
# 执行操作
ftp.retrlines('LIST')
except error_perm as e:
print(f"权限错误: {e}")
except error_temp as e:
print(f"临时错误(可重试): {e}")
except error_proto as e:
print(f"协议错误: {e}")
except Exception as e:
print(f"其他错误: {e}")
finally:
try:
ftp.quit()
except:
pass
6.2 、使用上下文管理器
python
from ftplib import FTP
# 自定义上下文管理器
class FTPConnection:
def __init__(self, host, user='', passwd=''):
self.host = host
self.user = user
self.passwd = passwd
self.ftp = None
def __enter__(self):
self.ftp = FTP(self.host)
self.ftp.login(self.user, self.passwd)
return self.ftp
def __exit__(self, exc_type, exc_val, exc_tb):
if self.ftp:
self.ftp.quit()
# 使用示例
with FTPConnection('ftp.example.com', 'username', 'password') as ftp:
ftp.retrlines('LIST')
# 自动关闭连接
6.3、 最佳实践建议
- 始终使用
quit()或上下文管理器:确保连接被正确关闭 - 设置合理的超时时间:避免程序长时间挂起
- 使用被动模式 :
ftp.set_pasv(True)(默认开启) - 对大文件使用断点续传:提高传输可靠性
- 处理网络异常:实现重试机制
- 避免硬编码凭据:使用环境变量或配置文件
7、实际应用案例
7.1 、批量备份文件到 FTP 服务器
python
import os
from datetime import datetime
from ftplib import FTP
def backup_to_ftp(local_dir, remote_dir, ftp_host, ftp_user, ftp_pass):
"""将本地目录备份到 FTP 服务器"""
ftp = FTP(ftp_host)
ftp.login(ftp_user, ftp_pass)
# 创建带时间戳的备份目录
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
backup_path = f"{remote_dir}/backup_{timestamp}"
ftp.mkd(backup_path)
# 遍历本地文件并上传
for root, dirs, files in os.walk(local_dir):
for file in files:
local_path = os.path.join(root, file)
remote_path = f"{backup_path}/{file}"
with open(local_path, 'rb') as f:
ftp.storbinary(f'STOR {remote_path}', f)
print(f"已上传: {file}")
ftp.quit()
print(f"备份完成,保存至: {backup_path}")
# 使用示例
backup_to_ftp(
local_dir='/home/user/documents',
remote_dir='/backups',
ftp_host='ftp.example.com',
ftp_user='username',
ftp_pass='password'
)
7.2、 定时同步远程文件
python
import schedule
import time
from ftplib import FTP
def sync_remote_files():
"""定时同步远程文件到本地"""
ftp = FTP('ftp.example.com')
ftp.login('username', 'password')
# 获取远程文件列表
remote_files = ftp.nlst('/data')
for remote_file in remote_files:
local_path = f"./local_data/{remote_file.split('/')[-1]}"
# 检查本地文件是否存在
try:
with open(local_path, 'rb') as f:
local_size = len(f.read())
remote_size = ftp.size(remote_file)
# 如果大小不同,重新下载
if local_size != remote_size:
with open(local_path, 'wb') as f:
ftp.retrbinary(f'RETR {remote_file}', f.write)
print(f"已更新: {remote_file}")
except FileNotFoundError:
# 本地文件不存在,直接下载
with open(local_path, 'wb') as f:
ftp.retrbinary(f'RETR {remote_file}', f.write)
print(f"已下载: {remote_file}")
ftp.quit()
# 每天凌晨 2 点执行同步
schedule.every().day.at("02:00").do(sync_remote_files)
while True:
schedule.run_pending()
time.sleep(60)
8、 常见问题与解决方案
8.1 、连接超时
python
from ftplib import FTP
# 设置连接超时
ftp = FTP('ftp.example.com', timeout=30)
# 设置操作超时
ftp.timeout = 60
8.2、 中文文件名乱码
python
from ftplib import FTP
ftp = FTP('ftp.example.com')
ftp.login()
# 设置编码为 UTF-8
ftp.encoding = 'utf-8'
# 或者使用 GBK 编码
# ftp.encoding = 'gbk'
# 列出文件
ftp.retrlines('LIST')
8.3 、防火墙/NAT 环境下的连接问题
python
from ftplib import FTP
ftp = FTP('ftp.example.com')
ftp.login()
# 强制使用被动模式(解决主动模式下的连接问题)
ftp.set_pasv(True)
# 执行操作
ftp.retrlines('LIST')
9、总结
ftplib 作为 Python 标准库的一部分,提供了完整且易用的 FTP 客户端功能。通过本文的学习,您应该已经掌握了:
- FTP 连接与登录的基本方法
- 文件上传、下载、目录操作等核心功能
- 使用
FTP_TLS实现安全传输 - 断点续传、递归遍历等高级技巧
- 异常处理和最佳实践
在实际项目中,ftplib 可以轻松集成到自动化脚本、定时任务或 Web 应用中,帮助您高效地完成文件传输需求。如果您的项目需要更高级的功能(如 SFTP、异步 FTP 等),可以考虑使用 paramiko、aioftp 等第三方库。
二、示例代码
1、示例代码
python
import os
import threading
import time
from pyftpdlib.authorizers import DummyAuthorizer
from pyftpdlib.handlers import FTPHandler
from pyftpdlib.servers import FTPServer
from ftplib import FTP
# -------------------------- 配置 --------------------------
FTP_HOST = "127.0.0.1"
FTP_PORT = 2121 # 不用21,避开管理员权限问题
FTP_USER = "admin"
FTP_PWD = "123456"
ROOT_DIR = "./ftp_share"
os.makedirs(ROOT_DIR, exist_ok=True)
# -------------------------- FTP服务端 --------------------------
def start_ftp_server():
authorizer = DummyAuthorizer()
# 完整读写权限
authorizer.add_user(FTP_USER, FTP_PWD, ROOT_DIR, perm="elradfmwMT")
handler = FTPHandler
handler.authorizer = authorizer
# 被动端口范围(本地测试可选)
handler.passive_ports = range(60000, 60050)
server = FTPServer((FTP_HOST, FTP_PORT), handler)
print(f"✅ FTP Server running on {FTP_HOST}:{FTP_PORT}")
server.serve_forever()
# -------------------------- FTP客户端工具函数 --------------------------
def ftp_upload(ftp: FTP, local_path: str, remote_name: str):
"""上传本地文件到FTP服务器"""
with open(local_path, "rb") as f:
ftp.storbinary(f"STOR {remote_name}", f)
print(f"📤 上传成功: {remote_name}")
def ftp_download(ftp: FTP, remote_name: str, save_local: str):
"""从FTP下载文件保存到本地"""
with open(save_local, "wb") as f:
ftp.retrbinary(f"RETR {remote_name}", f.write)
print(f"📥 下载成功,保存为: {save_local}")
def ftp_list(ftp: FTP):
"""列出服务端文件"""
print("\n📂 服务端文件列表:")
ftp.retrlines("LIST")
print()
# -------------------------- 主流程 --------------------------
if __name__ == "__main__":
# 1. 在子线程启动FTP服务
server_thread = threading.Thread(target=start_ftp_server, daemon=True)
server_thread.start()
time.sleep(0.8) # 等待服务启动
# 2. 准备一个测试本地文件
test_upload_file = "upload_demo.txt"
with open(test_upload_file, "w", encoding="utf-8") as f:
f.write("Hello FTP Demo\nPython pyftpdlib + ftplib\n")
# 3. 客户端连接
ftp = FTP()
ftp.connect(FTP_HOST, FTP_PORT)
ftp.login(FTP_USER, FTP_PWD)
print("✅ 客户端登录成功")
# 4. 上传文件到服务器
ftp_upload(ftp, test_upload_file, "server_file.txt")
# 5. 查看服务器目录
ftp_list(ftp)
# 6. 从服务器下载文件
ftp_download(ftp, "server_file.txt", "downloaded_from_ftp.txt")
# 7. 关闭连接
ftp.quit()
print("\n✅ 全部测试完成!")
2、运行结果
python
(.venv) PS D:\user\01417804\桌面\PythonProject> python .\main.py
✅ FTP Server running on 127.0.0.1:2121
[I 2026-09-04 16:45:00] concurrency model: async
[I 2026-09-04 16:45:00] masquerade (NAT) address: None
[I 2026-09-04 16:45:00] passive ports: 60000->60049
[I 2026-09-04 16:45:00] >>> starting FTP server on 127.0.0.1:2121, pid=8404 <<<
[I 2026-09-04 16:45:01] 127.0.0.1:59954-[] FTP session opened (connect)
[I 2026-09-04 16:45:01] 127.0.0.1:59954-[admin] USER 'admin' logged in.
✅ 客户端登录成功
[I 2026-09-04 16:45:01] 127.0.0.1:59954-[admin] STOR D:\user\01417804\桌面\PythonProject\ftp_share\server_file.txt completed=1 bytes=43 seconds=0.015
📤 上传成功: server_file.txt
📂 服务端文件列表:
-rw-rw-rw- 1 owner group 43 Sep 04 08:45 server_file.txt
[I 2026-09-04 16:45:01] 127.0.0.1:59954-[admin] RETR D:\user\01417804\桌面\PythonProject\ftp_share\server_file.txt completed=1 bytes=43 seconds=0.016
📥 下载成功,保存为: downloaded_from_ftp.txt
✅ 全部测试完成![I 2026-09-04 16:45:01] 127.0.0.1:59954-[admin] FTP session closed (disconnect).
(.venv) PS D:\user\01417804\桌面\PythonProject>

