Indy FTP List方法中的Delphi Bug?

Ian*_*cis 7 delphi ftp indy

我正在尝试生成与某个文件掩码匹配的文件列表,而Indy会因此错误而失败

带有消息的EidReplyRFCError' .': 没有相应的文件和目录.

我尝试了几种变体,这就是结果:

FTP.List( aFiles, '', true ); =>这个有效

FTP.List( aFiles, '*.*', false ); =>这也有效

FTP.List( aFiles, '*.*', true ); =>这个失败了

FTP.List( aFiles, '*.zip', true ); =>这也失败了(尽管它是最新文档中的例子)

FTP.List( '*.*', false ); =>这个有效

FTP.List( '*.*', true ); =>这个失败了

我正在使用Delphi XE5和Indy版本10.6.如果相关,XE8中也存在同样的问题.

也许功能已经改变,文档现在错了,或者它是Indy中的一个错误?

我需要"细节",所以我也可以比较时间戳和大小.

Rem*_*eau 11

这不是一个错误TIdFTP.这在Indy文档中更是一个遗漏.

EIdReplyRFCError表示FTP服务器本身正在报告错误以响应TIdFTP.List()正在发送的命令.根据ADetails参数和TIdFTP's 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]
Run Code Online (Sandbox Code Playgroud)

从而:

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 *.*'
Run Code Online (Sandbox Code Playgroud)

请注意,所有"失败"的命令都有一些共同点 - 它们可能正在发送MLSD ASpecifier命令.

根据RFC 959,它定义LISTNLST命令:

列表(列表)

此命令使列表从服务器发送到被动DTP. 如果路径名指定目录或其他文件组,则服务器应传输指定目录中的文件列表.如果路径名指定文件,则服务器应发送有关该文件的当前信息.null参数表示用户当前的工作或默认目录. ...

姓名单(NLST)

此命令导致目录列表从服务器发送到用户站点. pathname应指定目录或其他特定于系统的文件组描述符; null参数表示当前目录....

根据RFC 3659,定义MLSD命令:

MLST和MLSD命令每个都允许一个可选参数. 此参数可以是目录名称,也可以是MLST文件名. 出于这些目的,"文件名"是服务器NVFS中不是目录的任何实体的名称.在支持TVFS的情况下,可以给出在当前工作目录中有效的任何TVFS相对路径名,或任何TVFS完全限定路径名. 如果给出了目录名,则MLSD必须返回指定目录内容的列表,否则它将发出501回复,并且不会打开数据连接. ...

如果没有给出参数,那么MLSD必须返回当前工作目录内容的列表,并且MLST必须返回一个列表,该列表提供有关当前工作目录本身的信息....

...

如果Client-FTP发送无效参数,则服务器FTP必须回复,错误代码为501.

*.*并且*.zip不是目录名,因此如果TIdFTP.List()发送MLSD *.*MLSD *.zip命令,服务器将失败.所以,按理说,TIdFTP.UseMLISTIdFTP.CanUseMLS在你的情况可能都为真(UseMLIS默认为true,并且CanUseMLS通常是真正的现代FTP服务器).

MLSD命令不支持LIST/ NLSTcommands这样的服务器端过滤.所以你不能用的东西喜欢*.**.zipMLSD.您必须检索完整的目录列表,然后忽略您不感兴趣的任何条目.否则,TIdFTP.UseMLIS在调用之前设置为False TIdFTP.List(),但是您可能会TIdFTP.DirectoryListing错误地解析某些服务器的目录列表,因为该LIST命令从未标准化,并且在整个互联网上使用了数百种自定义格式(为什么TIdFTP在Indy 10 LIST中使用时会包含数十种列表解析器).不同的是MLSx,它具有标准化的格式(这就是为什么它首先被引入,以替换它的缺点LIST).

因此,这一切都归结为 - 当TIdFTP.UseMLISTIdFTP.CanUseMLS都是真的时,ASpecifier 必须是空白或目录,而不是文件掩码.

TIdFTP.List()文件 确实是状态List()可能内部调用TIdFTP.ExtListDir()发送MLSD命令,但它并没有特别提到在这个特别的限制,ASpecifier在这种情况下参数:

如果CanUseMLS包含True,则调用ExtListDir以在ADest参数变量中捕获并存储FTP MLSD命令的结果,而不是LIST或NLST命令.在这种情况下,List方法中不执行其他处理,并退出该方法.

当ADetails为False时,使用FTP NLST命令仅在ADest字符串列表中返回文件或目录名称.当ADetails为True时,List可以使用FTP LIST命令返回FTP服务器相关的详细信息,包括文件大小,修改日期以及所有者,组和用户的文件权限.

TIdFTP.ExtListDir()文档 确实声明其输入参数必须是目录名,但是:

ExtListDir支持的MLSD命令接受目录列表的Adirectory中可选目录名或相对路径.如果在ADirectory中传递空字符串,则当前目录用于目录列表操作.

在旁注:该TIdFTP.DirFormat属性将告诉您在TIdFTP.DirectoryListing解析结果后检测到哪种列表格式.或者你可以看看DetailsUsedMLS属性TListFTP.ListResult(类型投它TIdFTPListResult来访问属性)来推断该命令由发送TIdFTP.List()(如果成功的话).