必须用retrbinary()二进制下载xml并wb写入,再按utf-8解码;连接失败主因是认证错误、端口/协议不匹配或被动模式被防火墙拦截;下载后需校验文件大小和bom确保完整性。

ftplib 下载 XML 文件时乱码或内容损坏
FTP 协议本身不区分文本/二进制,ftplib 默认以 ASCII 模式传输,遇到 XML 中的 UTF-8 BOM、中文、换行符或特殊控制字符就会出错——表现是下载后的 .xml 文件打开报解析错误,或 xml.etree.ElementTree.parse() 报 UnicodeDecodeError 或 ParseError。
必须显式切换为二进制模式,且后续按需解码:
- 用
retrbinary()替代retrlines(),避免自动换行符转换和编码干扰 - 写入文件时用
open(..., "wb"),不加encoding参数 - 如果需要字符串处理,读取后用
.decode("utf-8")(注意检查 BOM 或服务器实际编码)
with open("data.xml", "wb") as f:
ftp.retrbinary("RETR remote.xml", f.write)
Python ftplib 连接 FTP 服务器失败的常见原因
连不上不是代码写错,大概率卡在认证或被动模式上。XML 文件本身不增加连接难度,但 FTP 配置稍有偏差就整个流程中断。
-
ftplib.error_perm: 530 Login incorrect:用户名/密码含特殊字符未做 URL 编码?确认是否需用ftp.login(user="u", passwd="p")显式传参,而非拼在 URL 里 -
ConnectionRefusedError或超时:检查 FTP 端口(默认 21),有些服务启用了 FTPS 或 SFTP——ftplib.FTP不支持加密协议,得换ftplib.FTP_TLS或pysftp -
OSError: [Errno 10060](Windows)或卡在connect():防火墙或路由器屏蔽了被动模式端口,调用ftp.set_pasv(True)(默认)后,可尝试设为False切回主动模式(需客户端开放高位端口)
下载远程 XML 后如何快速验证内容有效性
别急着扔给 ElementTree 解析——先确保字节流完整、编码干净。XML 文件哪怕少一个 >,解析器也会直接崩溃,而错误提示往往不指明是下载问题。
立即学习“Python免费学习笔记(深入)”;
- 检查文件大小:对比
ftp.size("remote.xml")和本地os.path.getsize("data.xml"),不一致说明传输中断 - 头几个字节看 BOM:
head = open("data.xml", "rb").read(4),UTF-8 BOM 是b"\xef\xbb\xbf",若开头是b"<?xml "就大概率没问题 - 用命令行快速验:终端运行
xmllint --noout data.xml(需安装 libxml2),比 Python 解析更早暴露格式问题
ftplib 下载大 XML 文件时内存暴涨或超时
retrbinary() 的回调函数如果把全部内容 accumulate 到一个 bytes 变量里,几 MB 的 XML 就可能吃光内存。别用 io.BytesIO 收集再写盘——这是新手最常踩的性能坑。
- 始终用文件对象直写:
open("out.xml", "wb")传给retrbinary(),不经过中间变量 - 如需边下边处理(比如流式提取某节点),用
iter+retrbinary()回调配合xml.sax,避免加载整树 - 设置超时:创建 FTP 实例时加
timeout=30,否则卡死在慢链路上没反馈
复杂点在于:XML 编码声明(<?xml version="1.0" encoding="GBK"?>)和实际字节流可能不一致,这时候 decode 失败不能怪 ftplib——得先读前几百字节判断编码,再选对方式解码。这事容易被忽略,但一出错就只能手动查 hex 值。









