【问题标题】:Delphi Bug in Indy FTP List method?Indy FTP List方法中的Delphi Bug?
【发布时间】:2015-09-01 06:24:23
【问题描述】:

我正在尝试生成与某个文件掩码匹配的文件列表,而 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 中的一个错误?

我需要“详细信息”,以便我也可以比较时间戳和大小。

【问题讨论】:

    标签: delphi ftp indy


    【解决方案1】:

    这不是TIdFTP 中的错误。更多的是 Indy 文档中的遗漏。

    EIdReplyRFCError 表示 FTP 服务器本身正在报告错误以响应TIdFTP.List() 正在发送的命令。根据ADetails 参数的值和TIdFTPUseMLIS+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,它定义了LISTNLST 命令:

    列表(列表)

    这个命令导致一个列表从服务器发送到 被动排版。 如果路径名指定一个目录或其他 文件组,服务器应传输文件列表 在指定的目录中。如果路径名指定一个 文件,那么服务器应该发送当前的信息 文件。空参数表示用户当前的工作或 默认目录。 ...

    名称列表(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.UseMLISTIdFTP.CanUseMLS 很可能都是 True(UseMLIS 默认为 True,CanUseMLS 在现代 FTP 服务器上通常为 True)。

    MLSD 命令不像LIST/NLST 命令那样支持服务器端过滤。所以你不能将*.**.zipMLSD 一起使用。您必须检索完整的目录列表,然后忽略您不感兴趣的任何条目。否则,在调用 TIdFTP.List() 之前将 TIdFTP.UseMLIS 设置为 False,但是您将面临 TIdFTP.DirectoryListing 错误地解析目录列表的风险一些服务器,因为 LIST 命令使用的格式从未标准化,并且整个 Internet 上使用了数百种自定义格式(以及为什么 Indy 10 中的 TIdFTP 包含数十个列表解析器,而 LIST 是用过的)。不像MLSx,它有一个标准化的格式(这就是为什么首先引入它,以取代LIST的缺点)。

    因此,这一切归结为 - 当 TIdFTP.UseMLISTIdFTP.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.ListResultDetailsUsedMLS 属性(将其类型转换为TIdFTPListResult 以访问属性)以推断TIdFTP.List() 发送了哪个命令(如果成功)。

    【讨论】:

    • 这是一个很好的解释雷米。非常有帮助。谢谢
    【解决方案2】:

    另一种解决方案是包含

    IdAllFTPListParsers

    在您的uses 子句中并禁用UseMLIS

    像这样:

    uses
      ....
      IdAllFTPListParsers;
       .....
    procedure TForm1.DoThis;
    var
      i: integer;
    begin
      if not IDFTP1.Connected then IDFTP1.Connect;
      IDFTP1.UseMLIS:= false;
      IDFTP1.List;
      for i:= 0 to IDFTP1.DirectoryListing.Count -1 do begin
        .. process directory items.
        IdFTP1.TransferType:= ftBinary;
        ..Get your files
    

    【讨论】:

    • 这存在解析错误的风险,无论是格式错误/自定义列表,还是以前未知的列表格式(Indy 有许多列表解析器,但它不会解析 所有内容存在于野外)。当 MLSx 可用时,UseMLIS=True 是首选。话虽如此,您所说的“如果 Indy 没有看到 ... 虚拟目录它会恐慌”是什么意思? TIdFTP 不关心这些条目,它们不必存在于列表中。那么它到底在恐慌什么呢?
    • @RemyLebeau,经过大量实验,这是对我有用的解决方案。如果你说./.. 虚拟目录没关系,我会重新调查。我相信你比我更了解情况。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多