ftplib需手动处理被动模式、SSL/TLS加密及断点续传:默认PASV易因NAT/防火墙失败,可set_pasv(False)切主动模式;FTP_TLS须login前调auth()和prot_p();上传用storbinary()防损坏,下载用retrbinary()保完整性,断点续传依赖服务器SITE REST支持。

ftplib 是 Python 标准库中轻量、可靠的选择,但默认不支持断点续传、SSL/TLS 自动协商和被动模式自动 fallback —— 你得手动处理这些,否则在防火墙后或上传大文件时大概率失败。
如何正确建立 FTP 连接并处理被动模式问题
很多 FTP 服务器(尤其是企业内网或云主机)强制要求被动模式(PASV),而 ftplib.FTP 默认开启被动模式,但某些网络环境会因 NAT 或防火墙导致 PASV 响应的 IP/端口不可达。此时需显式控制或降级为主动模式(PORT)。
- 连接后立即调用
ftp.set_pasv(True)(默认值,可省略),但若遇到error_perm: 500 Illegal PORT command或超时,尝试ftp.set_pasv(False) - 主动模式需客户端开放高位端口(通常 1024–65535),多数本地开发环境可行;生产环境建议优先调试 PASV,并确认服务器返回的 PASV 地址是否为公网 IP(常见坑:服务器返回内网 IP,如
227 Entering Passive Mode (192,168,1,100,123,45)) - 使用
FTP_TLS替代FTP时,必须在登录前调用ftp.auth()和ftp.prot_p()启用加密通道,否则凭据明文传输
上传文件时避免内存溢出与权限错误
用 storbinary() 上传大文件时,若直接传入 open(filename, 'rb'),Python 会按块读取,内存友好;但若误用 storlines() 上传二进制文件(如 zip、png),会导致内容损坏。
- 上传二进制文件(推荐):
ftp.storbinary(f'STOR {remote_path}', open(local_path, 'rb'), blocksize=8192) - 上传文本文件且需换行符转换(罕见):
ftp.storlines(f'STOR {remote_path}', open(local_path, 'r')),注意服务端可能把\n转成\r\n - 上传前建议先用
ftp.cwd()切到目标目录,或在STOR命令中写绝对路径(如/pub/data/report.zip) - 若报
error_perm: 550 Permission denied,检查远程路径是否存在、父目录是否有写权限,FTP 用户是否被 chroot 限制
下载文件时如何保证完整性与异常恢复
下载中断后无法续传是 ftplib 的硬伤 —— 它不暴露底层 socket 或 offset 控制。唯一稳妥方式是先用 ftp.size() 获取远端文件大小,再比对本地已下载字节数,手动截断重试。
安全 Python 代码沙箱:在隔离的沙箱中执行任意 Python 代码,预装 requests、NumPy、pandas 库。返回 stdout、stderr。
- 基础下载:
with open(local_path, 'wb') as f: ftp.retrbinary(f'RETR {remote_path}', f.write) - 带进度提示(简单):
ftp.retrbinary(f'RETR {remote_path}', lambda data: (f.write(data), print(f'\r{f.tell()} bytes', end=''))) - 断点续传模拟(需配合本地文件存在判断):
if os.path.exists(local_path): local_size = os.path.getsize(local_path); ftp.sendcmd(f'SITE REST {local_size}'); ... f.seek(0, 2) # append mode,但依赖服务器支持SITE REST命令(非标准,ProFTPD 支持,vsftpd 默认关闭) - 务必用
retrbinary()下载所有非纯文本文件;用retrlines()下载.txt或.csv时注意行尾符被服务端修改的风险
常见错误信息与对应排查动作
遇到报错别急着重试,先看错误类型再定位环节:
-
error_temp: 425 Can't open data connection→ 检查set_pasv()设置、防火墙是否放行数据端口、FTP 服务器 PASV 地址配置是否正确 -
error_perm: 530 Not logged in→ 忘记调用ftp.login(),或用户名密码为空字符串(login('', '')会触发匿名登录,部分服务器拒绝) -
OSError: [Errno 24] Too many open files→ 在循环上传/下载多个文件时未关闭ftp.quit()或未用with语句管理连接,导致 socket 句柄泄漏 -
UnicodeEncodeError: 'latin-1' codec can't encode character→ 远程路径含中文,而服务器编码不是 UTF-8;临时解法是用ftp.sendcmd(f'CWD {quote(remote_dir)}')对路径 URL 编码,或改用ftputil库替代
ftplib 的简洁性是一把双刃剑:它不隐藏细节,也就意味着每个网络异常、编码差异、权限边界都得你自己显式兜底。真正稳定跑通一个跨网络、跨平台的 FTP 脚本,80% 时间花在处理 PASV 兼容性、路径编码和连接生命周期管理上,而不是写 upload/download 函数本身。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










