I am using Indy IDFTP to make a directory. I need to find a reliable way to determine if a directory exists and if it does not exist, to call MakeDir. I have tried the following code but an exception did not occur when List was called so MakeDir was not executed even though the directory did not exist at the time. How can I determine if a directory exists and create the directory if it does not exist?
{ 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;
During my testing the directory did not exist but at runtime e was nil? Is my approach to this correct?
If TIdFTP.List()
is not raising an exception, the FTP server is most likely returning a 450
reply code, which simply means "Requested file action not taken". TIdFTP.InternalGet()
(which is used by TIdFTP.List()
, TIdFTP.ExtListDir()
, and TIdFTP.Get()
) does not treat 450
as an error condition, as some servers (like Ericsson Switch FTP) send 450
when listing the contents of an empty but otherwise existent directory, so there is no listing data to send. Some servers do send 450
when the requested directory does not exist, though. TIdFTP.List()
does not try to differentiate. However, if TIdFTP.List()
does not raise an exception, you can look at the TIdFTP.LastCmdResult
property to differentiate manually if needed.
Also, you can't just rely on the fact that an exception is raised to mean the folder does not exist. Any number of possible errors could occur. You have to actually look at the error and act accordingly, eg:
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;
A better way would be to either:
ChangeDir()
to the target directory directly and see if it fails. If so, start walking backwards through the path, calling ChangeDir()
for each parent directory until one finally succeeds, then walk back up the path using MakeDir()
and ChangeDir()
to create the missing sub-directories as needed.
Start with the first directory in the path and ChangeDir()
to it, then List()
it to see if the next sub-folder is present, MakeDir()
it if needed, then ChangeDir()
to it, and repeat as needed until you reach the target directory.
Welcome to FTP. It is not a very efficient protocol for directory management.