2017-10-06 96 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

谢谢雷米,它的工作完美,再加上给我一个方法来处理下载错误。 –