How to download a file with progress with IdHTTP v

2020-06-06 02:09发布

问题:

I'm trying to download a file using indy10 http components TIdHttp while getting the progress , I have just setted the libraries in the application folder while using the code for http URL it works and progress but with https it simply does nothing and it doesn't raises any exception :/

 with TIdHTTP.Create(nil) do
   begin
    IOHndl:=TIdSSLIOHandlerSocketOpenSSL.Create(nil);
    Request.BasicAuthentication:=True;
    HandleRedirects:=True;
    IOHandler:=IOHndl;
    OnWork:=FOnWork;
    OnWorkBegin:=FOnWorkBegin;
    OnWorkEnd:=FOnWorkEnd;
    Get(FUrl,FStream);
end;

Best Regards

回答1:

First you have to create a small class to wrap the HTTP component:

unit IdHTTPProgressU;

interface

uses
  Classes, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP, IdSSLOpenSSL;

{$M+}

type
  TIdHTTPProgress = class(TIdHTTP)
  private
    FProgress: Integer;
    FBytesToTransfer: Int64;
    FOnChange: TNotifyEvent;
    IOHndl: TIdSSLIOHandlerSocketOpenSSL;
    procedure HTTPWorkBegin(ASender: TObject; AWorkMode: TWorkMode; AWorkCountMax: Int64);
    procedure HTTPWork(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
    procedure HTTPWorkEnd(Sender: TObject; AWorkMode: TWorkMode);
    procedure SetProgress(const Value: Integer);
    procedure SetOnChange(const Value: TNotifyEvent);
  public
    Constructor Create(AOwner: TComponent);
    procedure DownloadFile(const aFileUrl: string; const aDestinationFile: String);
  published
    property Progress: Integer read FProgress write SetProgress;
    property BytesToTransfer: Int64 read FBytesToTransfer;
    property OnChange: TNotifyEvent read FOnChange write SetOnChange;
  end;

implementation

uses
  Sysutils;
{ TIdHTTPProgress }

constructor TIdHTTPProgress.Create(AOwner: TComponent);
begin
  inherited;
  IOHndl := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  Request.BasicAuthentication := True;
  HandleRedirects := True;
  IOHandler := IOHndl;
  ReadTimeout := 30000;
  OnWork := HTTPWork;
  OnWorkBegin := HTTPWorkBegin;
  OnWorkEnd := HTTPWorkEnd;
end;

procedure TIdHTTPProgress.DownloadFile(const aFileUrl: string; const aDestinationFile: String);
var
  LDestStream: TFileStream;
  aPath: String;
begin
  Progress := 0;
  FBytesToTransfer := 0;
  aPath := ExtractFilePath(aDestinationFile);
  if aPath <> '' then
    ForceDirectories(aPath);

  LDestStream := TFileStream.Create(aDestinationFile, fmCreate);
  try
    Get(aFileUrl, LDestStream);
  finally
    FreeAndNil(LDestStream);
  end;
end;

procedure TIdHTTPProgress.HTTPWork(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
begin
  if BytesToTransfer = 0 then // No Update File
    Exit;

  Progress := Round((AWorkCount / BytesToTransfer) * 100);
end;

procedure TIdHTTPProgress.HTTPWorkBegin(ASender: TObject; AWorkMode: TWorkMode; AWorkCountMax: Int64);
begin
  FBytesToTransfer := AWorkCountMax;
end;

procedure TIdHTTPProgress.HTTPWorkEnd(Sender: TObject; AWorkMode: TWorkMode);
begin
  FBytesToTransfer := 0;
  Progress := 100;
end;

procedure TIdHTTPProgress.SetOnChance(const Value: TNotifyEvent);
begin
  FOnChance := Value;
end;

procedure TIdHTTPProgress.SetProgress(const Value: Integer);
begin
  FProgress := Value;
  if Assigned(FOnChance) then
    FOnChance(Self);
end;

end.

I wont go in to details with the calss: Just say that it bacally wraps a TIdhttp component in and assign the 3 events: OnBegin, onWork and OnEnd

The Method DownloadFile does the actually download,

Then when you have to use it you could do like this:
Place a Button and a PrograssBar on an empty form. Add IdHTTPProgressU to the uses list.

Declare a vaiable of TIdHTTPProgress and a local onChangeEvent

Your form definition should lokke like this:

type
  TForm1 = class(TForm)
    Button1: TButton;
    ProgressBar1: TProgressBar;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    procedure IdHTTPProgressOnChange(Sender : TObject);
  public
    IdHTTPProgress: TIdHTTPProgress;
  end;

Then you just have to implement the methods:

    { TForm1 }

    procedure TForm1.Button1Click(Sender: TObject);
    begin
       IdHTTPProgress.OnChange := IdHTTPProgressOnChance;
          IdHTTPProgress.OnChance := IdHTTPProgressOnChance;
   IdHTTPProgress.DownloadFile('https://wordpress.org/latest.zip', 'latest.zip');
    end;

    procedure TForm1.FormCreate(Sender: TObject);
    begin
      IdHTTPProgress := TIdHTTPProgress.Create(Self);
    end;

    procedure TForm1.IdHTTPProgressOnChance(Sender: TObject);
    begin
      ProgressBar1.Position := TIdHTTPProgress(Sender).Progress;
      Application.ProcessMessages;
    end;

Thats about it. Give it at try.