递归列出FTP根目录所有子目录的所有文件和子目录。。。请大家帮忙支个招....

时间:2022-06-01 20:12:49
procedure TForm1.SynchronizationServerToClient;
var
  FileList: TStringList;
  i: integer;
  FtpItems: TIdFTPListItems; 
begin
  try
    if not ftp.Connected then exit;
    FileList := TStringList.Create;
    try
      ftp.List(FileList);
      FtpItems := TIdFTPListItems.Create;
      FtpItems := ftp.DirectoryListing;
      for i := 0 to FtpItems.Count - 1 do
      begin
        if FtpItems.Items[i].FileName[1] <> '.' then
          if FtpItems.Items[i].ItemType = ditDirectory then
          begin
            ShowMessage(FtpItems.Items[i].FileName);
            ftp.ChangeDir(FtpItems.Items[i].FileName);
            showmessage('before当前目录:' + ftp.RetrieveCurrentDir);
            SynchronizationServerToClient;
            showmessage('after当前目录:' + ftp.RetrieveCurrentDir);
            //ftp.ChangeDir('..');
            ftp.ChangeDirUp;
          end
          else
          begin
            ShowMessage(FtpItems.Items[i].FileName);
          end;
      end;
    finally
      FileList.Free;
    end;
  except
    showmessage('Error当前目录:' + ftp.RetrieveCurrentDir);
  end;
end;
递归进入子目录的时候正常,但是递归退到根目录的时候老报下面错误,大家帮忙分析分析!
    Project Project1.exe raised exception class EListError with message 'List index out of bounds (3)'. Process stopped. Use Step or Run to continue.

   我自己认为是IDFTP组件的List和DirectoryListing返回的值不相同,但是找不到解决办法,不知道是否跟FTP服务器有关系,我的是Serv-U 5.0 Beta.

17 个解决方案

#1


或者那位兄弟计算机上安装有FTP,用上面的代码帮我测试测试也行...

#2


呵呵

Serv-U等服务器支持List -a参数的,不需要使用递归这么低效率的方法,一次就可以获得全部列表的

LYFTP就全面支持List -A或递归搜索获取服务器的目录信息

http://lysoft.7u7.net

#3


支持么? 我试验了一下,好像不支持list -a?

#4


当然支持的,连IIS的FTP都可以!

Indy本来是不支持的,你需要修改IdFTP.pas的代码,呵呵

http://lysoft.7u7.net

#5


老兄,你说的List -a是通过什么方式执行的?麻烦说的详细点,我的大脑已经被搞晕了。

我在命令行执行ls -a返回的还是本目录下的文件和目录,没有列出子目录中的文件和子目录。

#6


我试验了一下上面的程序

有同样的问题,我觉得是不是因为每一次递归都要

create几个东西造成的,于是将递归放在一个过程中

这样似乎好了,但是有其他问题。

#7


不是吧,
难道Serv-U服务器支持,而Indy客户端不支持?
那还是搞不成啊!

#8


TO: zoologist(王朝) 
    我觉得是不是因为每一次递归都要create几个东西造成的.
    

你说的Create几个东西是指?不太明白,也许我没有想到。

#9


up

#10


搞错那么点,应该是List -R才是
自己下载LYFTP来研究了

再具体细节不便公开的

http://lysoft.7u7.net

#11


list -r 也不好用啊?

我的意思是

    FileList := TStringList.Create;
    FtpItems := TIdFTPListItems.Create;

这样的,并且每一次create后又没有destroy不知道会不会影响。

#12


递归是不能Destroy的,因为进入递归的时候把创建对象压入堆栈了。如果释放了的话,后面就会报错的。
    搞定:  ftp.List(str,'-R', true); 可以列出全部的文件和子目录。
    谢谢 ly_liuyang(Liu Yang)。

#13


最好能够用递归的方法实现,兄弟们帮帮忙了。

因为List -R 得到的列表信息乱得很,不只包含目录名和文件名,还有其它的东西。

#14


procedure TFMain.Button1Click(Sender: TObject);
var
  FileList: TStringList;
  FtpItems: TIdFTPListItems;
procedure getOne;
var
  i: integer;
begin
      ftpClient.List(FileList);
      FtpItems := ftpClient.DirectoryListing;      
      for i := 0 to FtpItems.Count - 1 do
      begin
        if FtpItems.Items[i].FileName[1] <> '.' then
          if FtpItems.Items[i].ItemType = ditDirectory then
          begin
            ShowMessage(FtpItems.Items[i].FileName);
            ftpClient.ChangeDir(FtpItems.Items[i].FileName);
            showmessage('before当前目录:' + ftpClient.RetrieveCurrentDir);
            GetOne;
            showmessage('after当前目录:' + ftpClient.RetrieveCurrentDir);
            ftpClient.ChangeDirUp;
          end
          else
          begin
            ShowMessage(FtpItems.Items[i].FileName);
          end;
      end;
end;
begin
  try
    if not ftpClient.Connected then exit;
    FileList := TStringList.Create;
    try
      ftpClient.List(FileList);
      FtpItems := TIdFTPListItems.Create;
      FtpItems := ftpClient.DirectoryListing;
      getOne;
    finally
      FileList.Free;
    end;
  except
    showmessage('Error当前目录:' + ftpClient.RetrieveCurrentDir);
  end;
end;

#15


TO: zoologist(王朝)
  你的算法在你那边可以成功吗?我这儿还是报:Project Project1.exe raised exception class EListError with message 'List index out of bounds (3)'. Process stopped. Use Step or Run to continue.

#16


贴一个console 可运行

program listall;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  IdBaseComponent,
  IdComponent,
  IdTCPConnection,
  IdTCPClient,
  IdFTP,
  IdFTPList,
  Classes;

var
 FTP:TIdFTP;

procedure ListThem(CurrentDir:String);
var
   LS:TIdFTPListItems;
   FileCount:Integer;
   tempLst:TStringList;
begin
  FTP.ChangeDir(CurrentDir);
  tempLst:=TStringList.Create;
  FTP.List(tempLst);
  LS:=TIdFTPListItems.Create;
  LS.Assign(FTP.DirectoryListing);
  for FileCount:=0 to LS.Count-1 do
    begin
      if LS.Items[FileCount].ItemType = ditDirectory then
        begin
          if (LS.Items[FileCount].FileName<>'.')
           and (LS.Items[FileCount].FileName<>'..')
             then
               begin
                 writeln('Entering...'+LS.Items[FileCount].FileName);
                 ListThem(CurrentDir+'/'+LS.Items[FileCount].FileName);
               end;
        end
      else
        begin
          if LS.Items[FileCount].FileName='logo.jpg' then
          write('err!');
          writeln('File:',LS.Items[FileCount].FileName);
        end;
    end;
  if CurrentDir<>'/' then
              begin
                FTP.ChangeDirUp;
                CurrentDir:=FTP.RetrieveCurrentDir;
              end;
end;

begin

   FTp:=TidFTP.Create(nil);
  FTP.Username:='anonymous';
  FTP.Password:='asdasd';
  FTP.Host:='172.18.18.85';
  FTP.Port:=21;
  FTP.Connect;
  writeln(FTP.LoginMsg.GenerateReply);
  ListThem('/');

  FTP.Disconnect;
  readln;
end.


#17


我搞定了,就是通过分析List -a返回的内容解决的,虽然很烦,但是总算个解决方案了。

#1


或者那位兄弟计算机上安装有FTP,用上面的代码帮我测试测试也行...

#2


呵呵

Serv-U等服务器支持List -a参数的,不需要使用递归这么低效率的方法,一次就可以获得全部列表的

LYFTP就全面支持List -A或递归搜索获取服务器的目录信息

http://lysoft.7u7.net

#3


支持么? 我试验了一下,好像不支持list -a?

#4


当然支持的,连IIS的FTP都可以!

Indy本来是不支持的,你需要修改IdFTP.pas的代码,呵呵

http://lysoft.7u7.net

#5


老兄,你说的List -a是通过什么方式执行的?麻烦说的详细点,我的大脑已经被搞晕了。

我在命令行执行ls -a返回的还是本目录下的文件和目录,没有列出子目录中的文件和子目录。

#6


我试验了一下上面的程序

有同样的问题,我觉得是不是因为每一次递归都要

create几个东西造成的,于是将递归放在一个过程中

这样似乎好了,但是有其他问题。

#7


不是吧,
难道Serv-U服务器支持,而Indy客户端不支持?
那还是搞不成啊!

#8


TO: zoologist(王朝) 
    我觉得是不是因为每一次递归都要create几个东西造成的.
    

你说的Create几个东西是指?不太明白,也许我没有想到。

#9


up

#10


搞错那么点,应该是List -R才是
自己下载LYFTP来研究了

再具体细节不便公开的

http://lysoft.7u7.net

#11


list -r 也不好用啊?

我的意思是

    FileList := TStringList.Create;
    FtpItems := TIdFTPListItems.Create;

这样的,并且每一次create后又没有destroy不知道会不会影响。

#12


递归是不能Destroy的,因为进入递归的时候把创建对象压入堆栈了。如果释放了的话,后面就会报错的。
    搞定:  ftp.List(str,'-R', true); 可以列出全部的文件和子目录。
    谢谢 ly_liuyang(Liu Yang)。

#13


最好能够用递归的方法实现,兄弟们帮帮忙了。

因为List -R 得到的列表信息乱得很,不只包含目录名和文件名,还有其它的东西。

#14


procedure TFMain.Button1Click(Sender: TObject);
var
  FileList: TStringList;
  FtpItems: TIdFTPListItems;
procedure getOne;
var
  i: integer;
begin
      ftpClient.List(FileList);
      FtpItems := ftpClient.DirectoryListing;      
      for i := 0 to FtpItems.Count - 1 do
      begin
        if FtpItems.Items[i].FileName[1] <> '.' then
          if FtpItems.Items[i].ItemType = ditDirectory then
          begin
            ShowMessage(FtpItems.Items[i].FileName);
            ftpClient.ChangeDir(FtpItems.Items[i].FileName);
            showmessage('before当前目录:' + ftpClient.RetrieveCurrentDir);
            GetOne;
            showmessage('after当前目录:' + ftpClient.RetrieveCurrentDir);
            ftpClient.ChangeDirUp;
          end
          else
          begin
            ShowMessage(FtpItems.Items[i].FileName);
          end;
      end;
end;
begin
  try
    if not ftpClient.Connected then exit;
    FileList := TStringList.Create;
    try
      ftpClient.List(FileList);
      FtpItems := TIdFTPListItems.Create;
      FtpItems := ftpClient.DirectoryListing;
      getOne;
    finally
      FileList.Free;
    end;
  except
    showmessage('Error当前目录:' + ftpClient.RetrieveCurrentDir);
  end;
end;

#15


TO: zoologist(王朝)
  你的算法在你那边可以成功吗?我这儿还是报:Project Project1.exe raised exception class EListError with message 'List index out of bounds (3)'. Process stopped. Use Step or Run to continue.

#16


贴一个console 可运行

program listall;

{$APPTYPE CONSOLE}

uses
  SysUtils,
  IdBaseComponent,
  IdComponent,
  IdTCPConnection,
  IdTCPClient,
  IdFTP,
  IdFTPList,
  Classes;

var
 FTP:TIdFTP;

procedure ListThem(CurrentDir:String);
var
   LS:TIdFTPListItems;
   FileCount:Integer;
   tempLst:TStringList;
begin
  FTP.ChangeDir(CurrentDir);
  tempLst:=TStringList.Create;
  FTP.List(tempLst);
  LS:=TIdFTPListItems.Create;
  LS.Assign(FTP.DirectoryListing);
  for FileCount:=0 to LS.Count-1 do
    begin
      if LS.Items[FileCount].ItemType = ditDirectory then
        begin
          if (LS.Items[FileCount].FileName<>'.')
           and (LS.Items[FileCount].FileName<>'..')
             then
               begin
                 writeln('Entering...'+LS.Items[FileCount].FileName);
                 ListThem(CurrentDir+'/'+LS.Items[FileCount].FileName);
               end;
        end
      else
        begin
          if LS.Items[FileCount].FileName='logo.jpg' then
          write('err!');
          writeln('File:',LS.Items[FileCount].FileName);
        end;
    end;
  if CurrentDir<>'/' then
              begin
                FTP.ChangeDirUp;
                CurrentDir:=FTP.RetrieveCurrentDir;
              end;
end;

begin

   FTp:=TidFTP.Create(nil);
  FTP.Username:='anonymous';
  FTP.Password:='asdasd';
  FTP.Host:='172.18.18.85';
  FTP.Port:=21;
  FTP.Connect;
  writeln(FTP.LoginMsg.GenerateReply);
  ListThem('/');

  FTP.Disconnect;
  readln;
end.


#17


我搞定了,就是通过分析List -a返回的内容解决的,虽然很烦,但是总算个解决方案了。