Upload file to FTP Server using Indy
I have struggled a bit with Indy Ftp over the years. At some point I turned to an alternative (free) Ftp client from OverbyteIcs (click ICS and then click Download ICS-V8.16 (Apr, 2015)). If you are not against using a freeware package, the following code will do the job:
uses
...
OverbyteIcsFtpCli;
procedure FtpUploadFile(
HostName: String;
UserName: String;
Password: String;
UploadFileName: String;
ToHostDir : String );
var
FTP: TFtpClient;
begin
FTP := TFtpClient.Create(nil);
try
FTP.HostName := HostName;
FTP.Passive := True;
FTP.Binary := True;
FTP.Username := UserName;
FTP.Password := Password;
FTP.Port := '21';
if not FTP.Open then
raise Exception.Create('Failed to connect: ' + FTP.ErrorMessage);
if (not FTP.User) or (not FTP.Pass) then
raise Exception.Create('Failed to login: ' + FTP.ErrorMessage);
FTP.HostDirName := ToHostDir;
if not FTP.Cwd then
raise Exception.Create('Failed to change dir: ' + FTP.ErrorMessage);
FTP.LocalFileName := UploadFileName;
FTP.HostFileName := ExtractFileName(UploadFileName);
if not FTP.Put then
raise Exception.Create('Failed to upload file: ' + FTP.ErrorMessage);
finally
FTP.Free;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
FtpUploadFile('rubilaxe.hostoi.com',
'******', '******',
IncludeTrailingPathDelimiter(
ExtractFilePath(Application.ExeName) ) +'datafile.zip',
'/files' );
end;
TheGreenOmega
Updated on June 04, 2022Comments
-
TheGreenOmega almost 2 years
I am unable to upload a file to my 000webhost.com FTP Server using Indy for Lazarus. I've tested the ftp connectivity with Windows Command Prompt, and it works fine. These are my Settings (IdFTP):
IdFTP1.Host:='shabala.com'; IdFTP1.Passive:=True; IdFTP1.TransferType:=ftBinary; IdFTP1.Username:='******'; IdFTP1.Password:='******'; IdFTP1.Port:=21;
And this is the code which I use to call my TIdFTP component, IdFTP1:
IdFTP1.Connect(True); //IdFTP1.ChangeDir('/Sessions'); IdFTP1.Put(GetCurrentDir+'\'+Token+'.cmd',Token+'.cmd', False); IdFTP1.Quit; IdFTP1.Disconnect;
where the variable
Token
is declared as:Token: String;
When I ran the program for the first time, it kept freezing and I declared a TIdAntiFreeze component to prevent it from freezing. So, this is what happens now: sometimes the program works fine, but no files are transferred to the server (If I try to repeat the upload, it gives me an EIdAlredyConnected error), and sometimes (if I change the code a bit, nothing extra) it gives me an EIdProtocolReplyError with a strange message. I tried to catch the exception and get my program to display the message, and I've got some strange characters:
$ £ ï túÁÕÖ îÖõ)€¶K…ÅõÞl%ÇðåÀ¨Á“§pp
A¨%˜ßï7!ƒDªÉ[…oˆ_£P*¡°z1K¢H€Î¨ERPö/
üð΃ç±ïpļƒÏƒ‹Ò1ì
¿Á{»(g{å¥r…Ž¹öÐR_JúѯuBûŸ€Œ Pp6o¯c[JgžÎ¿Èà¦Ä€VJþz’0è–`BO@TThe response looks like this if formatted correctly:
I couldn't put the formatted text here directly.
The server works absolutely fine, the directories I'm trying to upload to are chmodded to 777, and I've discovered that the file's size (which I want to upload) isn't greater than 3 KBs.
Any ideas?
-
Jerry Dodge over 8 yearsBy "bugging" I assume you mean "freezing" - since you attempted to use
TIdAntiFreeze
to solve it? -
TheGreenOmega over 8 yearsYes. The button which the procedure is assigned to remained in "Clicked State". It is a TBCButton (package BGRAControls). Also, the application wasn't responding (If I clicked on the form, it crashed). @JerryDodge
-
Remy Lebeau over 8 yearsThat is because
TIdFTP
blocks the calling thread while it is busy doing work (as do all of Indy's components). If the calling thread is the main UI thread, you prevent it from processing new messages in a timely manner, unless you useTIdAntiFreeze
. Better to move theTIdFTP
to a worker thread instead. -
TheGreenOmega over 8 years@RemyLebeau The graphics don't matter. TIdAntiFreeze works just fine. That's not my problem. My problem is that I still can't get the upload to work. Moving the TIdFTP component to another thread won't help... And I still have no idea what caused those strange responses. Anyways, thanks for the suggestion.
-
Remy Lebeau over 8 yearsDon't use
GetCurrentDir()
, it relies on the calling process's current working directory, which changes value during the process's lifetime. If the local file is in your app's folder, useExtractFilePath(Application.ExeName)
instead. In any case, what you have shown is not an FTP response, and certainly should never appear in anEIdProtocolReplyError
exception, which makes me wonder if you are actually connected to a real FTP server and not something else. -
Remy Lebeau over 8 yearsAnd the only way you can get
EIdAlreadyConnected
is ifConnected()
returns true when callingConnect()
.Connected()
returns true ifTIdFTP
is actually connected to a server, or if disconnected but there is still unread data in theIOHandler.InputBuffer
from an earlier connection. Don't callQuit()
, it is deprecated, just callDisconnect()
by itself. And if you callDisconnect()
in reply to a raised exception, clear theInputBuffer
of unread data:IdFTP1.Disconnect; if Assigned(IdFTP1.IOHandler) then IdFTP1.IOHandler.InputBuffer.Clear;
-
TheGreenOmega over 8 years@RemyLebeau If I'm not connected to the FTP server, then how can I get the EIdAlredyConnected exception? There's no leftover in the
InputBuffer
, I checked it. My greatest problem is that I can't finish the upload procedure. To check where the program hangs on, I created and assigned an OnWorkEnd event with theShowMessage('Upload done!');
code inside. The OnWorkEvent is never executed. -
Remy Lebeau over 8 years@TheGreenOmega: The only way for
EIdAlreadyConnected
to be raised is ifConnected()
returns true whenConnect()
is called (Connect()
checksConnected()
internally), and the only way forConnected()
to return true is if the socket is physically connected to a server (or at least a disconnect has not been detected yet) or theIOHandler
is still open and itsInputBuffer
has unread data. IfOnWorkBegin
is triggered,OnWorkEnd
is guaranteed to be triggered, unless a deadlock is occurring in between the two events. -
TheGreenOmega over 8 years@RemyLebeau Let's consider that the connection is active. I still can't upload files. What am I doing wrong?
-
Remy Lebeau over 8 yearsThe only way to get
EIdAlreadyConnected
in the code you showed is if you callConnect()
, thenPut()
orQuit()
raises an exception bypassingDisconnect()
, then you callConnect()
again. As for theEIdProtocolReplyError
, I can't answer that without seeing the original server response that triggered it.
-