![]() |
ProgressBar while FTP retreive - Printable Version +- Atozed Forums (https://www.atozed.com/forums) +-- Forum: Indy (https://www.atozed.com/forums/forum-8.html) +--- Forum: Indy General Discussion (https://www.atozed.com/forums/forum-9.html) +--- Thread: ProgressBar while FTP retreive (/thread-3236.html) |
ProgressBar while FTP retreive - zsleo - 05-18-2023 I need users to download large files (up to 800 MB) using Indy FTP. I am able to update the progress bar using TTask for some other lengthy processes but as soon as I start the FTP get file the procress bar stops updating. Does anyone have a soultion for this issue. TIA RE: ProgressBar while FTP retreive - rlebeau - 05-18-2023 (05-18-2023, 03:51 AM)zsleo Wrote: I need users to download large files (up to 800 MB) using Indy FTP. Like most components in Indy, TIdFTP blocks the calling thread until the requested operation is finished. Are you performing the FTP transfer in the context of the main UI thread or a worker thread? If the former, are you using TIdAntiFreeze to keep servicing the main UI message queue while the FTP transfer is busy? If the latter, are you synchronizing with the main UI thread, such as with TThread.Synchronize()/TThread.Notify(), or TIdSync/TIdNotify, etc? Can you provide your actual FTP code? RE: ProgressBar while FTP retreive - zsleo - 05-19-2023 (05-18-2023, 07:54 PM)rlebeau Wrote:(05-18-2023, 03:51 AM)zsleo Wrote: I need users to download large files (up to 800 MB) using Indy FTP. TidAntiFreeze is in the ServerController. I have TidFTPClient in UserSessionUnit with the following events Code: procedure TIWUserSession.idftp1Work(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64); In my Main Form I have an TIWTimer and Button with its OnClick calls the following procedure Code: procedure TiwfrmMain.OnDoFTP(Sender: TObject; AParams: TStringList); TIWTimer.Interval is set to 200 and the async event as follows Code: procedure TiwfrmMain.iwtmr1AsyncTimer(Sender: TObject; EventParams: TStringList); RE: ProgressBar while FTP retreive - rlebeau - 05-19-2023 (05-19-2023, 03:11 AM)zsleo Wrote: TidAntiFreeze is in the ServerController. I'm not familiar with IntraWeb or how it works. What thread does the ServerController run in? TIdAntiFreeze does nothing if invoked in a worker thread. (05-19-2023, 03:11 AM)zsleo Wrote: In my Main Form I have an TIWTimer and Button with its OnClick calls the following procedure Why are you running a TTask that effectively does nothing? All it does is Sleep() until gv_ToStop is True. That is a useless waste of a worker thread. (05-19-2023, 03:11 AM)zsleo Wrote: TIWTimer.Interval is set to 200 and the async event as follows You are calling GetFile() (and thus running TIdFTP) in the context of the thread that fires the timer event, so you are blocking your timer while the FTP transfer is in progress, which is why the timer is not able to update your ProgressBar. I strongly suggest that you move your FTP transfer logic to a separate worker thread. Do not block your timer handler. RE: ProgressBar while FTP retreive - zsleo - 05-22-2023 (05-19-2023, 04:25 PM)rlebeau Wrote:(05-19-2023, 03:11 AM)zsleo Wrote: TidAntiFreeze is in the ServerController. The ServerController is the main thread hence TidAntiFreeze being placed there. The TTask was experimental and it has been removed. Thanks for the advice. I will change the test FTP implementation you suggested. Thanks again. RE: ProgressBar while FTP retreive - Neerarawat - 06-22-2023 The issue you're experiencing with the progress bar not updating during the FTP file transfer process might be due to blocking the UI thread. The FTP Get operation is likely blocking the UI thread, preventing it from updating the progress bar. To address this issue, you can perform the FTP file transfer operation in a separate thread or task, allowing the UI thread to continue updating the progress bar. Here's an example of how you can achieve this using TThread: Code: procedure TForm1.DownloadFile(const AHost, AUsername, APassword, ARemoteFile, ALocalFile: string); In this example, the DownloadFile procedure sets up an FTP connection and starts the download in a separate thread using TThread.CreateAnonymousThread. The progress bar is updated in the FTPWork event handler, which is called during the FTP operation. The FTPWorkBegin event handler sets the maximum value of the progress bar, and the FTPWorkEnd event handler hides the progress bar when the FTP work is complete. Make sure to replace the FTP connection details (AHost, AUsername, APassword) and the file paths (ARemoteFile, ALocalFile) with your specific values. By executing the FTP operation in a separate thread, the UI thread remains responsive and can continue updating the progress bar. RE: ProgressBar while FTP retreive - rlebeau - 06-22-2023 (06-22-2023, 03:51 PM)Neerarawat Wrote: The issue you're experiencing ... First off, that felt like a ChatGPT-generated answer to me, but I'm going to address it anyway, because it provided a lot of misinformation that will get you into trouble. (06-22-2023, 03:51 PM)Neerarawat Wrote: Here's an example of how you can achieve this using TThread DO NOT call TIdFTP.Connected() from a different thread than the one that is performing the FTP operations. Connected() determines the socket state by reading from the socket, so you would be reading socket data from 2 threads at the same time, and thus risking the IOHandler.InputBuffer becoming corrupted, which would screw up the FTP operations. A safer approach would be to wait for the thread itself to terminate after the FTP work is finished. Note that TThread.CreateAnonymousThread() creates a TThread object whose FreeOnTerminate property is set to True, which means you would not be able to use the TThread.WaitFor() method by default without crashing your code. But, you can just turn off FreeOnTerminate before starting the anonymous thread. Also, since the FTP operations are being executed in a worker thread, the FTP.OnWork... event handlers will be called in the context of that thread, not in the context of the main UI thread. So, you would need to synchronize with the main thread when accessing UI controls. Try something more like this instead: Code: procedure TForm1.DownloadFile(const AHost, AUsername, APassword, ARemoteFile, ALocalFile: string); Which, to be honest, is really no better than simply eliminating the anonymous thread altogether and just having DownloadFile() use TIdFTP directly in the context of the calling thread, and using TIdAntiFreeze to avoid blockage if DownloadFile() is being called in the context of the main UI thread: Code: procedure TForm1.DownloadFile(const AHost, AUsername, APassword, ARemoteFile, ALocalFile: string); That being said, regardless of whichever thread ends up using TIdFTP, do note that for TIdFTP.Get() (but not for TIdFTP.Put()), the AWorkCountMax parameter of the TIdFTP.OnWorkBegin event will always be 0, because the FTP protocol does not advertise data sizes during transfers. So, you would need to use either TIdFTP.Size(), TIdFTP.List(), or TIdFTP.ExtListItem() to determine a file's size before you then use TIdFTP.Get() to download the file. I'll leave that as an exercise for you to add that to the above example. |