2010-08-23 51 views
7

我想從我的Delphi程序下載一個文件在一個單獨的線程專用於下載。從互聯網下載文件,同時能夠中止下載任何時間

問題是主程序可以隨時關閉(因此下載線程也可以隨時終止)。因此,即使沒有連接或服務器滯後寶貴的秒數,我也需要一種方法在一秒鐘或兩秒內終止下載線程。

你們推薦使用什麼功能?

我已經嘗試過使用InterOpenURL/InternetReadFile,但它沒有超時參數。它有一個異步版本,但我找不到任何工作的德爾福的例子,我不知道如果異步版本會保護我免受掛起...

使用套接字已被推薦給我之前,但TClientSocket doesn似乎也沒有超時功能。

我需要做好充分準備,所以如果用戶在他/她的計算機上有互聯網連接問題,或者網絡服務器保持滯後,我的應用程序在關閉之前不會掛起。

請記住,在回答我不想使用任何第三方組件或Indy。任何示例代碼非常感謝。

謝謝!

+0

的'InternetReadFile'可以在一個循環中獲取字節任意數量的調用。如果將它與線程中的Terminated檢查組合在一起,請在關閉應用程序時標記線程以終止並等待線程終止,則不應該有任何「掛起」。 – 2010-08-23 14:47:52

回答

2

TWinSocketStream有超時。您基本上創建了一個阻塞套接字,然後使用該套接字創建一個TWinSocketStream進行讀/寫操作。 (有點像使用StreamWriter)。然後循環直到連接關閉,線程終止,或者達到期望的字節數。有一個WaitForData()允許你檢查輸入數據是否超時,所以你永遠不會超過該超時值「鎖定」。

但是,你必須自己處理http進程。即發送'GET',然後讀取響應頭以確定需要多少字節,但那不是太困難。

+0

你碰巧有一些示例代碼? :-) – Steve 2010-08-23 21:16:15

+1

唉,不是個人。我通常使用突觸庫來處理這類事情。我確實在網上找到了 - 它看起來不錯,但是YMMV。 http://delphi.xcjc.net/viewthread.php?tid=29580這個例子使用了socketthread,但是原理是一樣的 - 等待數據,讀取數據,如果超時退出。 – GrandmasterB 2010-08-23 21:36:22

5

This Works。

var 
    DownloadAbort: boolean; 

procedure Download(const URL, FileName: string); 
var 
    hInet: HINTERNET; 
    hURL: HINTERNET; 
    Buffer: array[0..1023] of AnsiChar; 
    BufferLen, amt: cardinal; 
    f: file; 
const 
    UserAgent = 'Delphi Application'; // Change to whatever you wish 
begin 
    DownloadAbort := false; 
    hInet := InternetOpen(PChar(UserAgent), INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0); 
    try 
    hURL := InternetOpenUrl(hInet, PChar(URL), nil, 0, 0, 0); 
    try 
     FileMode := fmOpenWrite; 
     AssignFile(f, FileName); 
     try 
     Rewrite(f, 1); 
     repeat 
      InternetReadFile(hURL, @Buffer, SizeOf(Buffer), BufferLen); 
      BlockWrite(f, Buffer[0], BufferLen, amt); 
      if DownloadAbort then 
      Exit; 
     until BufferLen = 0; 
     finally 
     CloseFile(f); 
     end; 
    finally 
     InternetCloseHandle(hURL); 
    end; 
    finally 
    InternetCloseHandle(hInet); 
    end; 
end; 

在實踐中,上面的代碼將是你的線程的Execute方法的一部分,而你並不需要DownloadAbort; intead,你檢查

if Terminated then 
    Exit; 
+0

你好!如果InternetReadFile掛起,上面的代碼將不起作用。在發佈我的問題之前,我已瀏覽了幾個小時,並閱讀了這些情況的報告。 – Steve 2010-08-23 15:39:43

+0

@Steve:你有沒有發現InternetReadFile掛起?通常,您可以信任Windows API。畢竟,數百萬開發者每天都在使用它。 – 2010-08-23 15:59:43

+0

不難找到有關它的信息,例如查看這個信息:http://www.codeguru.com/forum/archive/index.php/t-355462.html 但是,如果你想一想,那裏有很多地方可能會出現問題:用戶的Internet連接問題,非工作代理問題,無線路由器問題,互聯網服務器響應緩慢......我認爲即使是InternetOpenURL也可能會掛起。 所以我需要的功能不會等待響應,但立即給予控制權,並在需要時允許取消。 任何想法? – Steve 2010-08-23 16:23:16

2

感謝GrandmasterB,這裏是我已經成功地放在一起碼:(這是在我的線程的執行塊)

var 
    Buffer: array [0..1024 - 1] of Char; 
    SocketStream: TWinSocketStream; 
    RequestString: String; 
    BytesRead: Integer; 
begin 
    try 
    ClientSocket.Active := true; 
    DownloadedData := ''; 
    FillChar(Buffer, SizeOf(Buffer), #0); 

    if not Terminated then 
    begin 
     // Wait 10 seconds 
     SocketStream := TWinSocketStream.Create(ClientSocket.Socket, 10000); 
     try 
     // Send the request to the webserver 
     RequestString := 'GET /remotedir/remotefile.html HTTP/1.0'#13#10 + 
      'Host: www.someexamplehost.com'#13#10#13#10; 
     SocketStream.Write(RequestString[1], Length(RequestString)); 

     // We keep waiting for the data for 5 seconds 
     if (not Terminated) and SocketStream.WaitForData(5000) then 
      repeat 
      // We store the data in our buffer 
      BytesRead := SocketStream.Read(Buffer, SizeOf(Buffer)); 

      if BytesRead = 0 then 
       break 
      else 
       DownloadedData := DownloadedData + Buffer; 
      until Terminated or (not SocketStream.WaitForData(2000)); 
     finally 
     // Close the connection 
     SocketStream.Free; 
     if ClientSocket.Active then 
      ClientSocket.Active := false; 
     end; 
    end; 
    except 
    end; 

你必須把這個線程的構造函數:

ClientSocket := TClientSocket.Create(nil); 
    ClientSocket.Host := 'www.someexamplehost.com'; 
    ClientSocket.Port := 80; 
    ClientSocket.ClientType := ctBlocking; 

    inherited Create(false); // CreateSuspended := false; 

這給desctructor:

ClientSocket.Free; 
    inherited; 
+0

看起來不錯!響應將在其中包含http響應標題,因此您收到的文件實際上將在兩個連續的#D#A之後開始,它們將標題與數據分開。當您收到響應頭中指定的字節數時,您可以立即關閉套接字 - 這將防止最後5秒掛起,同時等待查看是否有更多數據即將到來。 – GrandmasterB 2010-08-24 18:05:26

1

delphi.about.com


uses ExtActns, ... 

type 
    TfrMain = class(TForm) 
    ... 
    private 
    procedure URL_OnDownloadProgress 
     (Sender: TDownLoadURL; 
     Progress, ProgressMax: Cardinal; 
     StatusCode: TURLDownloadStatus; 
     StatusText: String; var Cancel: Boolean) ; 
    ... 

implementation 
... 

procedure TfrMain.URL_OnDownloadProgress; 
begin 
    ProgressBar1.Max:= ProgressMax; 
    ProgressBar1.Position:= Progress; 
end; 

function DoDownload; 
begin 
    with TDownloadURL.Create(self) do 
    try 
    URL:='http://0.tqn.com/6/g/delphi/b/index.xml'; 
    FileName := 'c:\ADPHealines.xml'; 
    OnDownloadProgress := URL_OnDownloadProgress; 

    ExecuteTarget(nil) ; 
    finally 
    Free; 
    end; 
end; 

{ 注: URL屬性指向互聯網 FileName是本地文件 }

相關問題