2013-05-02 47 views
3

我一直在使用Synapse一段時間,主要發送電子郵件。今天我正在創建一個簡單的安裝程序,並嘗試通過HTTP下載應用程序exe文件。該文件大小約爲9 MB,因此我想向用戶添加進度狀態,但我不瞭解我找到的示例。以下是我走到這一步:德爾福 - 使用Synapse下載包含進度的文件

type 
    THookSocketStatus = Procedure(Sender: TObject; Reason: THookSocketReason; const Value: String) of Object; 
    CallBack = class 
    Class Procedure Status(Sender: TObject; Reason: THookSocketReason; const Value: String); 
    end; 


Class Procedure CallBack.Status(Sender: TObject; Reason: THookSocketReason; const Value: String); 
var 
    V: String; 
Begin 
    V := GetEnumName(TypeInfo(THookSocketReason), Integer(Reason)) + ' ' + Value; 
    Form1.mem1.Lines.Add(V); 
    application.ProcessMessages; 
end; 

procedure TForm1.btn1Click(Sender: TObject); 
var 
    HTTP: THTTPSend; 
    MSTM: TMemoryStream; 
begin 
    Screen.Cursor := crHourGlass; 
    HTTP := THTTPSend.Create; 
    MSTM := TMemoryStream.Create; 
    Try 
    Try 
     HTTP.Sock.OnStatus := CallBack.Status; 
     If HTTP.HTTPMethod('GET', edt1.Text) Then 
     Begin 
     MSTM.Seek(0, soFromBeginning); 
     MSTM.CopyFrom(HTTP.Document, 0); 
     MSTM.SaveToFile(ExtractFilePath(Application.ExeName) + 'test.exe'); 
     end; 
    Except 
    end; 
    Finally 
    MSTM.Free; 
    HTTP.Free; 
    Screen.Cursor := crDefault; 
    end; 
end; 

在這個簡單的測試,我得到了這樣的結果:

HR_SocketClose 
HR_ResolvingBegin www.website.com:80 
HR_ResolvingEnd 176.102.295.18:80 
HR_SocketCreate IPv4 
HR_Connect www.website.com:80 
HR_WriteCount 158 
HR_CanRead 
HR_ReadCount 288 
HR_CanRead 
HR_ReadCount 8192 
HR_ReadCount 8192 
HR_ReadCount 8192 
HR_ReadCount 6720 
HR_CanRead 
HR_ReadCount 3299 
. 
. 
. 
HR_ReadCount 8192 
HR_ReadCount 8192 
HR_ReadCount 7828 
HR_SocketClose 
HR_SocketClose 

請什麼樣的手段WriteCount和ReadCount?如何在開始下載之前獲取總文件大小以設置進度欄?

謝謝你們!

+0

我相信字節數讀取或寫入。如果內容不是文本,則應該能夠訪問從GET請求返回的標題,然後查找「內容長度:3495」中的「內容長度」並獲取文件總大小。不幸的是,我從來沒有使用Synapse,所以我不能提供更多的指導。 – Glenn1234 2013-05-02 21:28:15

+0

嗨@ Glenn1234,謝謝。我將嘗試獲取有關如何獲取GET標題的更多信息。 – Guybrush 2013-05-02 21:47:04

+0

好吧,我放棄了試圖用Synapse做到這一點。我再次使用Indy,這樣做更容易。不管怎樣,謝謝你! – Guybrush 2013-05-03 15:28:19

回答

2

我有同樣的問題,並通過擴展上面的代碼找到了解決方案。文件長度如上所述通過使用標題信息可用。

這裏是我的代碼:

unit uhttpdownloader; 


{$mode Delphi}{$H+} 

interface 

uses 
    Classes, SysUtils, httpsend, blcksock, typinfo; 

//Interface for notifications about the progress 
type 
    IProgress = interface 
    procedure ProgressNotification(Text: String; CurrentProgress : integer; MaxProgress : integer); 
    end; 

type 
    { THttpDownloader } 

    THttpDownloader = class 
    public 
    function DownloadHTTP(URL, TargetFile: string; ProgressMonitor : IProgress): Boolean; 
    private 
    Bytes : Integer; 
    MaxBytes : Integer; 
    HTTPSender: THTTPSend; 
    ProgressMonitor : IProgress; 
    procedure Status(Sender: TObject; Reason: THookSocketReason; const Value: String); 
    function GetSizeFromHeader(Header: String):integer; 
    end; 

implementation 

function THttpDownloader.DownloadHTTP(URL, TargetFile: string; ProgressMonitor : IProgress): Boolean; 
var 
    HTTPGetResult: Boolean; 
begin 
    Result := False; 
    Bytes:= 0; 
    MaxBytes:= -1; 
    Self.ProgressMonitor:= ProgressMonitor; 

    HTTPSender := THTTPSend.Create; 
    try 
    //add callback function for status updates 
    HTTPSender.Sock.OnStatus:= Status; 
    HTTPGetResult := HTTPSender.HTTPMethod('GET', URL); 
    if (HTTPSender.ResultCode >= 100) and (HTTPSender.ResultCode<=299) then begin 
     HTTPSender.Document.SaveToFile(TargetFile); 
     Result := True; 
    end; 
    finally 
    HTTPSender.Free; 
    end; 
end; 

//Callback function for status events 
procedure THttpDownloader.Status(Sender: TObject; Reason: THookSocketReason; const Value: String); 
var 
    V, currentHeader: String; 
    i: integer; 
begin 
    //try to get filesize from headers 
    if (MaxBytes = -1) then 
    begin 
    for i:= 0 to HTTPSender.Headers.Count - 1 do 
    begin 
     currentHeader:= HTTPSender.Headers[i]; 
     MaxBytes:= GetSizeFromHeader(currentHeader); 
     if MaxBytes <> -1 then break; 
    end; 
    end; 

    V := GetEnumName(TypeInfo(THookSocketReason), Integer(Reason)) + ' ' + Value; 

    //HR_ReadCount contains the number of bytes since the last event 
    if Reason = THookSocketReason.HR_ReadCount then 
    begin 
    Bytes:= Bytes + StrToInt(Value); 
    ProgressMonitor.ProgressNotification(V, Bytes, MaxBytes); 
    end; 
end; 

function THttpDownloader.GetSizeFromHeader(Header: String): integer; 
var 
    item : TStringList; 
begin 
    //the download size is contained in the header (e.g.: Content-Length: 3737722) 
    Result:= -1; 

    if Pos('Content-Length:', Header) <> 0 then 
    begin 
    item:= TStringList.Create(); 
    item.Delimiter:= ':'; 
    item.StrictDelimiter:=true; 
    item.DelimitedText:=Header; 
    if item.Count = 2 then 
    begin 
     Result:= StrToInt(Trim(item[1])); 
    end; 
    end; 
end; 
end. 

完整的源代碼和例子也可以在此處下載: http://andydunkel.net/lazarus/delphi/2015/09/09/lazarus_synapse_progress.html

安迪