IDFTP DirExists 和 MakeDir

IDFTP DirExists and MakeDir

我正在使用 Indy IDFTP 创建目录。我需要找到一种可靠的方法来确定目录是否存在,如果不存在,则调用 MakeDir。我尝试了以下代码,但是调用 List 时没有发生异常,因此即使目录当时不存在,也没有执行 MakeDir。如何判断一个目录是否存在,如果不存在则创建该目录?

{ Check to see if the '/public_html/XXX/' + iDomain + 'Thumbnails' directory exists }
    try
      IdFTP1.List(nil, '/public_html/XXX/' + iDomain + 'Thumbnails', False);
    except
      on e: EIdReplyRFCError do
      begin
        { '/public_html/XXX/' + iDomain + 'Thumbnails' directory does not exist }
        StatusBar1.SimpleText := 'Making thumbnail directory...';
        StatusBar1.Update;
        iFolder := '/public_html/XXX/' + iDomain;
        { Change directory to /public_html/XXX/iDomain }
        IdFTP1.ChangeDir(iFolder);
        iFolder := 'Thumbnails';
        { Create FTP Directory for Thumbnails }
        IdFTP1.MakeDir(iFolder);
      end;
    end;

在我测试期间目录不存在但在运行时 e 为零?我的做法是否正确?

如果 TIdFTP.List() 没有引发异常,则 FTP 服务器很可能返回 450 回复代码,即 "Requested file action not taken"。 TIdFTP.InternalGet()(由 TIdFTP.List()TIdFTP.ExtListDir()TIdFTP.Get() 使用)不会将 450 视为错误条件,因为某些服务器(如 Ericsson Switch FTP) 发送 450 列出一个空但存在的目录的内容,因此没有要发送的列表数据。但是,当请求的目录不存在时,某些服务器会发送 450TIdFTP.List() 不尝试区分。但是,如果 TIdFTP.List() 没有引发异常,您可以查看 TIdFTP.LastCmdResult 属性 以根据需要手动区分。

此外,您不能仅仅依靠引发异常这一事实来表示文件夹不存在。可能会发生任何数量的错误。您必须实际查看错误并采取相应措施,例如:

var
  Exists: Boolean;

try
  IdFTP1.List(nil, '/public_html/XXX/' + iDomain + 'Thumbnails', False);
  Exists := True;
  if IdFTP1.LastCmdResult.NumericCode = 450 then
  begin
    if (IdFTP1.LastCmdResult.Text.Text has a message like 'No such file or directory' or similar) then begin
      Exists := False;
    end;
    // look for other possible text messages...
  end;
except
  on e: EIdReplyRFCError do
  begin
    if (e.ErrorCode <> 550) or (e.Message does not have a message like 'Directory not found' or similar) then begin
      raise;
    end;
    Exists := false;
  end;
end;

if not Exists then
begin
  { '/public_html/XXX/' + iDomain + 'Thumbnails' directory does not exist }
  StatusBar1.SimpleText := 'Making thumbnail directory...';
  StatusBar1.Update;
  iFolder := '/public_html/XXX/' + iDomain;
  { Change directory to /public_html/XXX/iDomain }
  IdFTP1.ChangeDir(iFolder);
  iFolder := 'Thumbnails';
  { Create FTP Directory for Thumbnails }
  IdFTP1.MakeDir(iFolder);
end;

更好的方法是:

  1. ChangeDir()直接到目标目录,看是否失败。如果是这样,开始通过路径向后走,为每个父目录调用 ChangeDir() 直到最后成功,然后使用 MakeDir()ChangeDir() 返回路径以创建丢失的子目录根据需要。

  2. 从路径中的第一个目录开始 ChangeDir(),然后 List() 查看下一个子文件夹是否存在,MakeDir()如果需要它,然后 ChangeDir() 到它,并根据需要重复直到到达目标目录。

欢迎来到 FTP。它不是一个非常有效的目录管理协议。

这里是上传文件夹的方法。 Source.

{
  Upload the LocalDir to an FTP server, in the RemoteDir.
  If RemoteDir does not exist it is created.
  All files and subfolders of LocalDir will be uploaded.
  FTP parameters (username, password, server) must be already provided.
  The caller must connnect to the server before calling UploadFolderToFtp and disconnect after that }
procedure UploadFolderToFtp(FTP: TIdFTP; LocalDir, RemoteDir, Filter: string);


   procedure GoToSubDir(SubDir: string);
   VAR
     details, nodetails: TStringList;
     k: Integer;
   begin
    details   := TStringList.Create;       //get folder contents from ftp. one with details, one without
    nodetails := TStringList.Create;
    TRY
     FTP.List(details, '', True);
     FTP.List(nodetails, '', False);

     //we only want to have directories in the list (without '.' and '..')
     for k := details.Count - 1 downto 0 do
      if details.Strings[k] <> '' then
        if (PosInsensitive('dir', details.Strings[k]) < 1)
        OR (nodetails.Strings[k] = '.')
        OR (nodetails.Strings[k] = '..') then
         begin
          details.Delete(k);
          nodetails.Delete(k);
         end;

     //if our directory does not exists on the server, create it
     if nodetails.IndexOf(SubDir) = -1
     then FTP.MakeDir(SubDir);
    FINALLY
     FreeAndNil(Details);
     FreeAndNil(nodetails);
    END;
    FTP.ChangeDir(SubDir);   //change into next directory on server
   end;


   procedure uploadDir(dir: string);
   VAR
      s: string;
      List: TStringList;
   begin
     List:= ListDirectoriesOf(dir, FALSE, FALSE);        //iterate through subdirectories
     for s in List DO
      begin
       GoToSubDir(s);
       uploadDir(dir + s + '\');                         //and also locally go into the next subfolder
       FTP.ChangeDirUp;                                  //we have to go one directory up after leaving the recursion
      end;
     FreeAndNil(List);

     List:= ListFilesOf(dir, Filter, FALSE, FALSE);       //iterate through files
     for s in List DO
      begin
        Assert(s > '', 'File name should not be empty!');
        FTP.Put(dir + s, s);                           //if it's only a file, upload it to the current directory;
      end;
     FreeAndNil(List);
   end;


VAR
   subdir, dir: string;
begin
 //does not matter if RemoteDir is like 'dir\dir' or 'dir/dir'
 dir := StringReplace(RemoteDir, '\', '/', [rfReplaceAll]);

 if dir <> '' then
  begin
   if dir[1] = '/' then Delete(dir, 1, 1);     //remove first '/' if there's one
   if dir[Length(dir)] <> '/'  then dir := dir + '/';       // add a '/' at the end

   //loop through our remote-directories
   WHILE Pos('/', dir) > 0 DO
    begin
     SubDir:= system.Copy(dir, 1, Pos('/', dir) - 1);

     //if our directory does not exists on the server, we create it
     GoToSubDir(SubDir);

     //remove first directory from path ('your/directory/subdir/' --> 'directory/subdir/')
     Delete(dir, 1, Pos('/', dir));
    end;
  end;

 dir := LocalDir;
 if dir[Length(dir)] <> '\'
 then dir := dir + '\';

 uploadDir(dir);   // begin the upload
end;



procedure TfrmFTP.Button1Click(Sender: TObject);
begin
 if Connect       {Set parameters for FTP and connect to server }
 then UploadFolderToFtp(ftp, 'c:\test\', RemoteDir, '*.*')
 else SwMessage('Cannot connect to '+ FTP.ServerHOST);
 Disconnect;
end;

--

ListDirectoriesOf & ListFilesOf 是 returns 指定文件夹的 subdirectories/files 的函数(returns non-full 路径)

简单的解决方案是

      IdFTP.ChangeDir('/www/image/catalog/');  // connect to to directory where you want to add folder

      try
        IdFTP.MakeDir(new_Dir_name);          // try to create folder
        IdFTP.ChangeDir('/www/image/catalog/' + new_Dir_name );  // connect to new folder
      except
        IdFTP.ChangeDir('/www/image/catalog/' + new_Dir_name ); // if folder exist just connect to folder which exist
      end;