仲龙 發表於 2022-7-7 13:39:00

Delphi使用THTTPClient实现异步下载

<p>首先在接口部分需要引用System.Net.HttpClient类</p>
<div class="cnblogs_Highlighter">
<pre class="brush:delphi;gutter:true;">uses System.Net.HttpClient,System.IOUtils; </pre>
</div>
<p>初始化必需的变量参数</p>
<div class="cnblogs_Highlighter">
<pre class="brush:delphi;gutter:true;">    FClient: THTTPClient; //异步下载类
    FGlobalStart: Cardinal; //全局计时
    FAsyncResult: IAsyncResult; //set and get 异步调用的状态
    FDownloadStream: TStream; //下载流</pre>
</div>
<p>异步下载类的初始化:其中下方的ReceiveDataEvent方法表示响应下载的当前进度:滚动台、百分比等可视化内容可通过其展示给用户</p>
<div class="cnblogs_Highlighter">
<pre class="brush:delphi;gutter:true;">FClient := THTTPClient.Create; //初始化
FClient.OnReceiveData := ReceiveDataEvent;//下载数据进度接收事件
FClient.SecureProtocols := [THTTPSecureProtocol.TLS1,
    THTTPSecureProtocol.TLS11, THTTPSecureProtocol.TLS12];//协议类型 可自定义</pre>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:delphi;gutter:true;">procedure ReceiveDataEvent(const Sender: TObject;
AContentLength, AReadCount: Int64; var Abort: Boolean);
var
LTime: Cardinal;
LSpeed: Integer;
begin
LTime := TThread.GetTickCount - FGlobalStart;//片段事件
if LTime = 0 then
    Exit;
LSpeed := (AReadCount * 1000) div LTime;
//TThread.Queue 将线程放入主线程main窗体执行 用于显示进度
TThread.Queue(nil,
    procedure
    begin
      ProgressBarDownload.Value := AReadCount;
      LabelGlobalSpeed.Caption := Format('Global speed: %d KB/s',
      );
    end);
end;
</pre>
</div>
<p>在窗体上放置了一个启动的button按钮,在buttononclick事件中调用SampleDownload方法。SampleDownload方法为实际的下载启动操作</p>
<div class="cnblogs_Highlighter">
<pre class="brush:delphi;gutter:true;">procedure SampleDownload;
var
URL: string;
LResponse: IHTTPResponse;
LFileName: string;
LSize: Int64;
begin
LFileName := EditFileName.Text; //下载文件存放地址
try
    URL := EditUrl.Text; //下载地址

    LResponse := FClient.Head(URL); //获取请求头
    LSize := LResponse.ContentLength; //判断请求头的大小 是否请求成功
    Memo1.Lines.Add(Format('Head response: %d - %s', [LResponse.StatusCode,
      LResponse.StatusText]));//打印出请求状态 和 状态内容
    LResponse := nil; //释放请求头内容
    ProgressBarDownload.Maximum := LSize; //进度条的最大值 要注意的是vcl与fmx进度条maxium不同
    ProgressBarDownload.Minimum := 0; //进度条起点
    ProgressBarDownload.Value := 0; //进度条当前值
    LabelGlobalSpeed.Caption := 'Download speed: 0 KB/s';

    Memo1.Lines.Add(Format('Downloading: "%s" (%d Bytes) into "%s"',
      ));

    // Create the file that is going to be dowloaded
    FDownloadStream := TFileStream.Create(LFileName, fmCreate); //下载流初始化以及文件权限设置
    FDownloadStream.Position := 0; //下载流从起点开始 初始化

    // Start the download process
    FGlobalStart := TThread.GetTickCount;
    FAsyncResult := FClient.BeginGet(DoEndDownload, URL, FDownloadStream);//返回异步调用状态 以及 随时可控 可断

finally
    BStopDownload.Enabled := FAsyncResult &lt;&gt; nil; //判断异步调用状态
    BStartDownload.Enabled := FAsyncResult = nil; //释放
end;
end;<br><br>//接收下载的状态 包括自然下载成功或用户人为终止</pre>
<pre class="brush:delphi;gutter:true;">procedure DoEndDownload(const AsyncResult: IAsyncResult);
var
LAsyncResponse: IHTTPResponse;
begin
try
//判断异步调用的状态
    LAsyncResponse := THTTPClient.EndAsyncHTTP(AsyncResult);
//将此线程阻塞到主线程中去 在ui界面上告知用户操作状态
    TThread.Synchronize(nil,
      procedure
      begin
      if AsyncResult.IsCancelled then
          Memo1.Lines.Add('Download Canceled')
      else
      begin
          Memo1.Lines.Add('Download Finished!');
          Memo1.Lines.Add(Format('Status: %d - %s', [LAsyncResponse.StatusCode,
            LAsyncResponse.StatusText]));
      end;

      BStopDownload.Enabled := False;
      BStartDownload.Enabled := True;
      end);
finally
    LAsyncResponse := nil;
    FreeandNil(FDownloadStream);
end;
end;</pre>
</div>
<p>放置了一个停止的Button按钮,在buttononclick中调用FAsyncResult.Cancel;方法可终止下载操作。</p>
<p>完整代码如下:</p>
<div class="cnblogs_Highlighter">
<pre class="brush:delphi;gutter:true;">unit DownloadForm;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.Net.URLClient,
System.Net.HttpClient, System.Net.HttpClientComponent, Vcl.ComCtrls,
Vcl.StdCtrls, System.Types, Vcl.ExtCtrls;

type
TFormDownload = class(TForm)
    Panel1: TPanel;
    Label1: TLabel;
    Label2: TLabel;
    EditFileName: TEdit;
    EditUrl: TEdit;
    BStartDownload: TButton;
    LabelGlobalSpeed: TLabel;
    BStopDownload: TButton;
    Panel2: TPanel;
    Memo1: TMemo;
    ProgressBarDownload: TProgressBar;
    procedure BStartDownloadClick(Sender: TObject);
    procedure ReceiveDataEvent(const Sender: TObject; AContentLength: Int64;
      AReadCount: Int64; var Abort: Boolean);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure BStopDownloadClick(Sender: TObject);
private
    { Private declarations }
    FClient: THTTPClient;
    FGlobalStart: Cardinal;
    FAsyncResult: IAsyncResult;
    FDownloadStream: TStream;
    procedure SampleDownload;
    procedure DoEndDownload(const AsyncResult: IAsyncResult);
public
    { Public declarations }
end;

var
FormDownload: TFormDownload;

implementation

uses System.IOUtils;
{$R *.dfm}

procedure TFormDownload.BStopDownloadClick(Sender: TObject);
begin
(Sender as TButton).Enabled := False;
FAsyncResult.Cancel;
end;

procedure TFormDownload.DoEndDownload(const AsyncResult: IAsyncResult);
var
LAsyncResponse: IHTTPResponse;
begin
try
    LAsyncResponse := THTTPClient.EndAsyncHTTP(AsyncResult);
    TThread.Synchronize(nil,
      procedure
      begin
      if AsyncResult.IsCancelled then
          Memo1.Lines.Add('Download Canceled')
      else
      begin
          Memo1.Lines.Add('Download Finished!');
          Memo1.Lines.Add(Format('Status: %d - %s', [LAsyncResponse.StatusCode,
            LAsyncResponse.StatusText]));
      end;

      BStopDownload.Enabled := False;
      BStartDownload.Enabled := True;
      end);
finally
    LAsyncResponse := nil;
    FreeandNil(FDownloadStream);
end;
end;

procedure TFormDownload.ReceiveDataEvent(const Sender: TObject;
AContentLength, AReadCount: Int64; var Abort: Boolean);
var
LTime: Cardinal;
LSpeed: Integer;
begin
LTime := TThread.GetTickCount - FGlobalStart;
if LTime = 0 then
    Exit;
LSpeed := (AReadCount * 1000) div LTime;
TThread.Queue(nil,
    procedure
    begin
      ProgressBarDownload.Value := AReadCount;
      LabelGlobalSpeed.Caption := Format('Global speed: %d KB/s',
      );
    end);
end;

procedure TFormDownload.FormCreate(Sender: TObject);
begin
FClient := THTTPClient.Create;
FClient.OnReceiveData := ReceiveDataEvent;
FClient.SecureProtocols := [THTTPSecureProtocol.TLS1,
    THTTPSecureProtocol.TLS11, THTTPSecureProtocol.TLS12];
end;

procedure TFormDownload.FormDestroy(Sender: TObject);
begin
FDownloadStream.Free;
FClient.Free;
end;

procedure TFormDownload.BStartDownloadClick(Sender: TObject);
begin
BStartDownload.Enabled := False;
SampleDownload;
end;

procedure TFormDownload.SampleDownload;
var
URL: string;
LResponse: IHTTPResponse;
LFileName: string;
LSize: Int64;
begin
LFileName := EditFileName.Text;
try
    URL := EditUrl.Text;

    LResponse := FClient.Head(URL);
    LSize := LResponse.ContentLength;
    Memo1.Lines.Add(Format('Head response: %d - %s', [LResponse.StatusCode,
      LResponse.StatusText]));
    LResponse := nil;
    ProgressBarDownload.Maximum := LSize;
    ProgressBarDownload.Minimum := 0;
    ProgressBarDownload.Value := 0;
    LabelGlobalSpeed.Caption := 'Download speed: 0 KB/s';

    Memo1.Lines.Add(Format('Downloading: "%s" (%d Bytes) into "%s"',
      ));

    // Create the file that is going to be dowloaded
    FDownloadStream := TFileStream.Create(LFileName, fmCreate);
    FDownloadStream.Position := 0;

    // Start the download process
    FGlobalStart := TThread.GetTickCount;
    FAsyncResult := FClient.BeginGet(DoEndDownload, URL, FDownloadStream);

finally
    BStopDownload.Enabled := FAsyncResult &lt;&gt; nil;
    BStartDownload.Enabled := FAsyncResult = nil;
end;
end;

end.
</pre>
</div>
<p>  </p>
<p>使用上述方法,便可使用Delphi完成异步下载~Delphi是真的强大~超级大爱</p>
<p>原文地址:https://www.cnblogs.com/ne1620/p/16454384.html</p><br><br>
来源:https://www.cnblogs.com/ne1620/p/16454384.html
頁: [1]
查看完整版本: Delphi使用THTTPClient实现异步下载