Delphi 解析目录和子目录中的所有文件时出现IdFTP性能问题

Delphi 解析目录和子目录中的所有文件时出现IdFTP性能问题,delphi,indy,ftp-client,indy10,Delphi,Indy,Ftp Client,Indy10,我需要解析目录中的每个文件,包括子目录和子目录中的文件以及… 我已经使用下面的代码成功地完成了此操作: class function TATDFTPUtility.findAllDirectoryFiles(var ftpClient: TIdFTP; directory: String; deepness: Integer = 0): TidFTPListItems; var I: Integer; localDirectoryListing: TIdFTPListItems; b

我需要解析目录中的每个文件,包括子目录和子目录中的文件以及…
我已经使用下面的代码成功地完成了此操作:

class function TATDFTPUtility.findAllDirectoryFiles(var ftpClient: TIdFTP; directory: String; deepness: Integer = 0): TidFTPListItems;
var
  I: Integer;
  localDirectoryListing: TIdFTPListItems;
  baseDirectory: string;
begin
  Result := TIdFTPListItems.Create;
  *// this function uses ftpClient.ChangeDirUp until it reaches the '' directory*
  changeUpToDirectory(ftpClient, '');
  try
    ftpClient.ChangeDir(directory);
    ftpClient.List;
    Result.Assign(ftpClient.DirectoryListing);
    localDirectoryListing := Result;
    baseDirectory := ftpClient.RetrieveCurrentDir;
    for I := 0 to localDirectoryListing.Count - 1 do
    begin
      if (localDirectoryListing.Items[i].ItemType = ditDirectory) then
      begin
        result := addTwoFTPListItems(result, findAllDirectoryFiles(ftpClient, baseDirectory + '/' + localDirectoryListing.Items[i].FileName));
      end;
    end;
  except
  end;
end;

class function TATDFTPUtility.addTwoFTPListItems(listA: TIdFTPListItems; listB: TIdFTPListItems): TidFTPListItems;
var
  i: integer;
begin
  Result := listA;
  for I := 0 to listB.Count - 1 do
  begin
    with Result.Add do
    begin
      Data := listB.Items[i].data;
      Size := listB.Items[i].Size;
      ModifiedDate := listB.Items[i].ModifiedDate;
      LocalFileName := listB.Items[i].LocalFileName;
      FileName := listB.Items[i].FileName;
      ItemType := listB.Items[i].ItemType;
      SizeAvail := listB.Items[i].SizeAvail;
      ModifiedAvail := listB.Items[i].ModifiedAvail;
      PermissionDisplay := listB.Items[i].PermissionDisplay;
    end;
  end;
end;
现在的问题是这大约需要15-20分钟 还有更有效的方法吗?
以下是关于这个特殊案例的一些事实:
1-在我运行程序后,它发现了大约12000个文件,几乎有100-200个目录,但最高深度约为7
2-我只需要解析,不需要下载或上传任何内容

3-我使用异常的原因是,在FTP内部有一些我无权访问的文件夹,这导致
IdFTP中出现
访问冲突
错误,我使用
尝试…除了
忽略任何无法访问的目录。

您正在调用
ChangeDirUp()
(可能多次?)然后调用
ChangeDir()
。如果
directory
是一个绝对路径,您只需调用
ChangeDir()
一次即可直接跳转到目标文件夹,并避免
ChangeDirUp()
的全部调用。
findAllDirectoryFiles()中的递归循环
正在使用来自
RetrieveCurrentDir()
的绝对路径,因此重复调用
ChangeDirUp()
ChangeDir()
会浪费开销。不必在文件夹树上下导航,可以大大减少开销

findAllDirectoryFiles()
正在返回调用方必须释放的新分配的
tidftplitiems
。这本身通常是一个糟糕的设计选择,但在这种情况下尤其如此,因为递归循环根本没有释放那些次要的
tidftplitiems
对象,所以它们被泄漏

将文件添加到输出
TIdFTPListItems
时,您只添加了文件名而不是路径。如果调用者不知道每个文件的位置,递归搜索文件有什么好处?或者您只关心文件名而不关心路径

您完全忽略了
深度
参数

话虽如此,请尝试类似的方法:

class procedure TATDFTPUtility.findAllDirectoryFiles(ftpClient: TIdFTP; const directory: String;var files: TIdFTPListItems; deepness: Integer = -1);
var
  I: Integer;
  baseDirectory: string;
  subDirectories: TStringList;
  item: TIdFTPListItem;
  localDirectoryListing: TIdFTPListItems;
begin
  try
    if directory <> '' then
      ftpClient.ChangeDir(directory);
    ftpClient.List;
  except
    Exit;
  end;
  baseDirectory := ftpClient.RetrieveCurrentDir;
  localDirectoryListing := ftpClient.DirectoryListing;
  subDirectories := nil;
  try
    for I := 0 to localDirectoryListing.Count - 1 do
    begin
      case localDirectoryListing[i].ItemType of
        ditFile: begin
          item := files.Add;
          item.Assign(localDirectoryListing[i]);
          // if you need the full path of each file...
          item.FileName := baseDirectory + '/' + item.FileName;
        end;
        ditDirectory: begin
          item := localDirectoryListing[i];
          if ((item.FileName <> '.') and (item.FileName <> '..')) and
             ((deepness = -1) or (deepness > 0)) then
          begin
            if subDirectories = nil then
              subDirectories := TStringList.Create;
            subDirectories.Add(baseDirectory + '/' + item.FileName);
          end;
        end;
      end;
    end;
    if subDirectories <> nil then
    begin
      if (deepness > 0) then Dec(deepness);
      for I := 0 to subDirectories.Count - 1 do begin
        findAllDirectoryFiles(ftpClient, subDirectories[I], files, deepness);
      end;
    end;
  finally
    subDirectories.Free;
  end;
end;

谢谢你的回答!我不知道我可以使用绝对路径,我不需要使用
changeDirUp
!我还没有植入深度,这就是为什么它没有做任何事情,现在回到你的回答,我尝试了你的代码,当你调用
findAllDirectoryFiles()时,有一些问题
您正在使目录列表无效,这就是为什么我使用了一个额外的
FTPListItems
并分配了值,我对此进行了迭代,第二个必须是
J
,最重要的是还有一个逻辑错误!程序永远运行!!,我记录了它并注意到(阅读下一条评论)您额外的
tidftplitiems
对象是不必要的。此外,您建议的更改引入了新的内存泄漏,因此我已删除该更改。至于原始
目录列表
子目录
循环期间无效,这是因为我将该循环放在错误的位置。我现在已修复该问题(不需要额外的
TIdFTPListItems
对象副本).我注意到程序永远运行!我记录了它,看到它在进入文件夹和找到文件后循环返回,它出现一层,进入相同的文件夹并再次查看它们!我认为它只是无限地在最后两层循环,如果可以的话,我将尝试调试该函数。尝试最新的代码。它是不应重新扫描以前扫描过的文件夹(除非服务器碰巧正在使用重定向到文件夹层次结构中更高级别的文件夹的虚拟文件夹。但以前没有听说过,但也不常见)。我刚刚运行了您的代码,前面的问题已经解决,我的
日志显示“已解析文件计数=11587已解析文件夹计数=689”,这花费了16分钟!似乎每20个文件大约需要1秒,是否有可能更快的方法?
files := TIdFTPListItems.Create;
try
  TATDFTPUtility.findAllDirectoryFiles(ftpClient, 'desired directory', files, desired deepness);
  // use files as needed...
finally
  files.Free;
end;