这不是TIdFTP 中的错误。更多的是 Indy 文档中的遗漏。
EIdReplyRFCError 表示 FTP 服务器本身正在报告错误以响应TIdFTP.List() 正在发送的命令。根据ADetails 参数的值和TIdFTP 的UseMLIS+CanUseMLS 属性的值,List() 可以发送三种不同命令之一:
ADetails=False:
NLST [ASpecifier]
ADetails=True:
TIdFTP.UseMLIS=True and TIdFTP.CanUseMLS=True:
MLSD [ASpecifier]
TIdFTP.UseMLIS=False or TIdFTP.CanUseMLS=False:
LIST [ASpecifier]
因此:
FTP.List( aFiles, '', true ); // this works
// sends either 'LIST' or 'MLSD'
FTP.List( aFiles, '*.*', false ); // this works too
// sends 'NLST *.*'
FTP.List( aFiles, '*.*', true ); // this fails
// sends either 'LIST *.*' or 'MLSD *.*'
FTP.List( aFiles, '*.zip', true ); // this fails too
// sends either 'LIST *.zip' or 'MLSD *.zip'
FTP.List( '*.*', false ); // this works
// sends 'NLST *.*'
FTP.List( '*.*', true ); // this fails
// sends either 'LIST *.*' or 'MLSD *.*'
请注意,所有“失败”的命令都有一些共同点——它们可能发送MLSD ASpecifier 命令。
根据RFC 959,它定义了LIST 和NLST 命令:
列表(列表)
这个命令导致一个列表从服务器发送到
被动排版。 如果路径名指定一个目录或其他
文件组,服务器应传输文件列表
在指定的目录中。如果路径名指定一个
文件,那么服务器应该发送当前的信息
文件。空参数表示用户当前的工作或
默认目录。 ...
名称列表(NLST)
这个命令导致一个目录列表从
服务器到用户站点。 路径名应指定一个
目录或其他系统特定的文件组描述符;一种
null 参数表示当前目录。 ...
根据RFC 3659,它定义了MLSD 命令:
MLST 和 MLSD 命令各允许一个可选参数。
该参数可以是一个目录名,或者,仅对于 MLST,一个
文件名。 出于这些目的,“文件名”是任何
服务器 NVFS 中不是目录的实体。 TVFS 在哪里
支持,任何在当前工作中有效的 TVFS 相对路径名
可以给出目录或任何 TVFS 完全限定的路径名。 如果一个
给定目录名,则 MLSD 必须返回目录列表
指定目录的内容,否则它会发出 501 回复,并且
不打开数据连接。 ...
如果没有给出参数,那么 MLSD 必须返回一个列表
当前工作目录的内容,并且 MLST 必须返回一个
列出有关当前工作目录的信息
本身。 ...
...
如果客户端 FTP 发送一个无效参数,服务器 FTP 必须
回复错误代码 501。
*.* 和*.zip 不是目录名,因此如果TIdFTP.List() 发送MLSD *.* 或MLSD *.zip 命令,服务器将失败。因此,在您的情况下,TIdFTP.UseMLIS 和 TIdFTP.CanUseMLS 很可能都是 True(UseMLIS 默认为 True,CanUseMLS 在现代 FTP 服务器上通常为 True)。
MLSD 命令不像LIST/NLST 命令那样支持服务器端过滤。所以你不能将*.* 和*.zip 与MLSD 一起使用。您必须检索完整的目录列表,然后忽略您不感兴趣的任何条目。否则,在调用 TIdFTP.List() 之前将 TIdFTP.UseMLIS 设置为 False,但是您将面临 TIdFTP.DirectoryListing 错误地解析目录列表的风险一些服务器,因为 LIST 命令使用的格式从未标准化,并且整个 Internet 上使用了数百种自定义格式(以及为什么 Indy 10 中的 TIdFTP 包含数十个列表解析器,而 LIST 是用过的)。不像MLSx,它有一个标准化的格式(这就是为什么首先引入它,以取代LIST的缺点)。
因此,这一切归结为 - 当 TIdFTP.UseMLIS 和 TIdFTP.CanUseMLS 均为 True 时,ASpecifier 必须为空白或目录,不一个文件掩码。
TIdFTP.List() documentation 确实 声明List() 可以在内部调用TIdFTP.ExtListDir() 来发送MLSD 命令,但它并没有特别提到对ASpecifier 参数的这种特殊限制那个案例:
如果 CanUseMLS 包含 True,则调用 ExtListDir 以捕获 FTP MLSD 命令的结果并将其存储在 ADest 参数变量中,而不是 LIST 或 NLST 命令中。这种情况下List方法不做额外处理,退出方法。
当 ADetails 为 False 时,使用 FTP NLST 命令在 ADest 字符串列表中仅返回文件或目录名称。当 ADetails 为 True 时,List 可以使用 FTP LIST 命令返回与 FTP 服务器相关的详细信息,包括文件大小、修改日期以及所有者、组和用户的文件权限。
TIdFTP.ExtListDir() documentation确实声明它的输入参数必须是目录名,但是:
在 ExtListDir 中支持的 MLSD 命令接受 Adirectory 中的可选目录名称或相对路径作为目录列表。如果ADirectory中传入的是空字符串,则使用当前目录进行目录列表操作。
附带说明:TIdFTP.DirFormat 属性将告诉您在TIdFTP.DirectoryListing 解析结果后检测到哪种列表格式。或者您可以查看TListFTP.ListResult 的Details 和UsedMLS 属性(将其类型转换为TIdFTPListResult 以访问属性)以推断TIdFTP.List() 发送了哪个命令(如果成功)。