2017-10-06 149 views
1

我已經做了一個IdFTP從我的FTP服務器上下載文件,但是當我嘗試使它變爲螺紋時,它陷入了Android操作系統中的「正在解析主機名...」。正確地做一個線程FTP下載(Indy/Android)

無螺紋(工作正常):

uses ..., IdFTPCommon; 

var 
    RecordDownload: TMemoryStream; 

uses System.IOUtils; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    IdFTP1.Host := 'motoristaajudante.ddns.net'; 
    IdFTP1.Port := 2121; 
    IdFTP1.DataPortMin := 50100; 
    IdFTP1.DataPortMax := 51100; 
    IdFTP1.Username := 'anonymous'; 
    IdFTP1.TransferType := IdFTPCommon.TIdFTPTransferType.ftBinary; 
    IdFTP1.Passive := True; 
    try 
    IdFTP1.Connect(); 
    IdFTP1.Get('00001.m4a',TPath.GetDocumentsPath + PathDelim + '00001.m4a',True,False); 
    except 
    IdFTP1.Disconnect; 
    end; 
end; 

procedure TForm1.IdFTP1AfterGet(ASender: TObject; AStream: TStream); 
begin 
    IdFTP1.Disconnect; 
end; 

procedure TForm1.IdFTP1WorkEnd(ASender: TObject; AWorkMode: TWorkMode); 
begin 
    if FileExists(TPath.GetDocumentsPath + PathDelim + '00001.m4a') then 
    begin 
     ShowMessage('Downloaded!'); 
    end; 
end; 

和螺紋代碼我提出以下this solution

uses ..., IdFTPCommon; 

type 
    TLoadThread = class(TThread) 
    public 
    constructor Create; reintroduce; 
    protected 
    procedure Execute; override; 
    end; 

type 
    TForm1 = class(TForm) 
    ... 
    procedure ThreadTerminated(Sender: TObject); 

var 
    RecordDownload: TMemoryStream; 
    Loading: Boolean = False; 
    zLThread: TLoadThread = nil; 

uses System.IOUtils; 

constructor TLoadThread.Create; 
begin 
    inherited Create(True); 
    FreeOnTerminate := True; 
end; 

procedure TLoadThread.Execute; 
begin 
try 
    Form1.IdFTP1.Connect(); 
    Form1.IdFTP1.Get('00001.m4a',TPath.GetDocumentsPath + PathDelim + '00001.m4a',True,False); 
except 
    Form1.IdFTP1.Disconnect; 
end; 
end; 

procedure TForm1.ThreadTerminated(Sender: TObject); 
begin 
    zLThread := nil; 
    Loading := False; 
    FloatAnimation1.Enabled := False; 
    FloatAnimation2.Enabled := False; 
    Arc3.StartAngle := -90; 
    Arc3.EndAngle := 0; 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    IdFTP1.Host := 'motoristaajudante.ddns.net'; 
    IdFTP1.Port := 2121; 
    IdFTP1.DataPortMin := 50100; 
    IdFTP1.DataPortMax := 51100; 
    IdFTP1.Username := 'anonymous'; 
    IdFTP1.TransferType := IdFTPCommon.TIdFTPTransferType.ftBinary; 
    IdFTP1.Passive := True; 
    zLThread := TLoadThread.Create; 
    zLThread.OnTerminate := ThreadTerminated; 
    zLThread.Start; 
    Loading := True; 
    FloatAnimation1.Enabled := True; 
    FloatAnimation2.Enabled := True; 
end; 

procedure TForm1.IdFTP1AfterGet(ASender: TObject; AStream: TStream); 
begin 
    IdFTP1.Disconnect; 
end; 

procedure TForm1.IdFTP1WorkEnd(ASender: TObject; AWorkMode: TWorkMode); 
begin 
    Form1.FloatAnimation1.Enabled := False; 
    Form1.FloatAnimation2.Enabled := False; 
    Form1.Arc3.StartAngle := -90; 
    Form1.Arc3.EndAngle := 0; 
    if FileExists(TPath.GetDocumentsPath + PathDelim + '00001.m4a') then 
    begin 
     ShowMessage('Downloaded!'); 
    end; 
end; 

procedure TForm1.IdFTP1Status(ASender: TObject; const AStatus: TIdStatus; 
    const AStatusText: string); 
begin 
    Memo1.Lines.Add(AStatusText); 
    Application.ProcessMessages; 
end; 

然後FTP狀態顯示它停留在 「解決主機名...」。如何使它正確地線程化?

回答

4

沒有理由使用OnAfterGetOnWorkEnd事件與您使用它們的方式。 Indy是同步的。 TIdFTP.Get()直到傳輸完成纔會返回,如果發生錯誤則會引發異常。

所以,擺脫這兩個事件處理程序,使用try/finally而不是try/except打電話Disconnect(),並處理只有Get()不提高下載。

OnWorkEndOnStatus事件中調用Connect()Disconnect()Get()同一線程的上下文中觸發。因此,在你的線程示例中,這將是工作者線程,而不是主線程。但是,您的事件處理程序不會同步對UI控件的訪問。這可能會導致各種問題,包括您遇到的凍結。你必須同步TThread.OnTerminated事件是同步的)。

隨着中說,試試這個:

非螺紋:

uses 
    ..., IdFTPCommon; 

... 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    IdFTP1.Host := 'motoristaajudante.ddns.net'; 
    IdFTP1.Port := 2121; 
    IdFTP1.DataPortMin := 50100; 
    IdFTP1.DataPortMax := 51100; 
    IdFTP1.Username := 'anonymous'; 
    IdFTP1.TransferType := IdFTPCommon.TIdFTPTransferType.ftBinary; 
    IdFTP1.Passive := True; 
    try 
    IdFTP1.Connect; 
    try 
     IdFTP1.Get('00001.m4a', TPath.GetDocumentsPath + PathDelim + '00001.m4a', True, False); 
    finally 
     IdFTP1.Disconnect; 
    end; 
    ShowMessage('Downloaded!'); 
    except 
    ShowMessage('Error while downloading!'); 
    end; 
end; 

螺紋:

uses 
    ..., IdFTPCommon; 

type 
    TLoadThread = class(TThread) 
    public 
    constructor Create; reintroduce; 
    protected 
    procedure Execute; override; 
    end; 

type 
    TForm1 = class(TForm) 
    ... 
    IdFTP1: TIdFTP; 
    procedure ThreadTerminated(Sender: TObject); 
    ... 
    private 
    Loading: Boolean; 
    zLThread: TLoadThread; 
    end; 

... 

constructor TLoadThread.Create; 
begin 
    inherited Create(True); 
    FreeOnTerminate := True; 
end; 

procedure TLoadThread.Execute; 
begin 
    Form1.IdFTP1.Connect; 
    try 
    Form1.IdFTP1.Get('00001.m4a', TPath.GetDocumentsPath + PathDelim + '00001.m4a', True, False); 
    finally 
    Form1.IdFTP1.Disconnect; 
    end; 
end; 

procedure TForm1.ThreadTerminated(Sender: TObject); 
begin 
    zLThread := nil; 
    Loading := False; 
    FloatAnimation1.Enabled := False; 
    FloatAnimation2.Enabled := False; 
    Arc3.StartAngle := -90; 
    Arc3.EndAngle := 0; 
    If TThread(Sender).FatalException = nil then 
    ShowMessage('Downloaded!') 
    else 
    ShowMessage('Error while Downloading!'); 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    IdFTP1.Host := 'motoristaajudante.ddns.net'; 
    IdFTP1.Port := 2121; 
    IdFTP1.DataPortMin := 50100; 
    IdFTP1.DataPortMax := 51100; 
    IdFTP1.Username := 'anonymous'; 
    IdFTP1.TransferType := IdFTPCommon.TIdFTPTransferType.ftBinary; 
    IdFTP1.Passive := True; 
    zLThread := TLoadThread.Create; 
    zLThread.OnTerminate := ThreadTerminated; 
    zLThread.Start; 
    Loading := True; 
    FloatAnimation1.Enabled := True; 
    FloatAnimation2.Enabled := True; 
end; 

procedure TForm1.IdFTP1Status(ASender: TObject; const AStatus: TIdStatus; const AStatusText: string); 
begin 
    TThread.Queue(nil, 
    procedure 
    begin 
     Memo1.Lines.Add(AStatusText); 
    end 
); 
end; 
+0

謝謝雷米,它的工作完美,再加上給我一個方法來處理下載錯誤。 –