Como fazer Download de Arquivos com Progresso do andamento?
Fala galera do Show Delphi, tudo beleza?
Hoje estava precisando implementar nos meus sistemas um mecanismo para baixar arquivos.
Então pesquisando vi que podia fazer isso utilizando o TIDHttp, que é um componente do Indy que já acompanha o Delphi por padrão e também é possível instalar no Lazarus gratuitamente.
Legal, basicamente é assim: IDHttp1.Get(‘seu link’, variavelStream).
Bacana, vi que funcionava assim, mas eu queria que fosse exibido o andamento do download, para os casos de arquivos maiores.
Tentei algumas formas utilizando diretamente o TIDHttp, mas não tinha conseguido obter sucesso.
Então continuei pesquisando e encontrei um post no stackoverflow um post com um exemplo de como resolver este problema.
Peguei este exemplo testei e funcionou. Fiz alguns pequenos ajustes e agora o exemplo funciona também em Lazarus.
Ficou interessado? Então vamos ao código!
Seguinte, para iniciar, vamos criar uma unit com o nome util.download.
Nesta unit vamos implementar uma classe que herda de TIDHttp e adicionar algumas funções que nos permita verificar o andamento do download.
Segue o código com comentários sobre as etapas:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
| { }
{ TIdHTTPProgress - Extendend TIdHTTP to show progress download }
{ }
{ Creted in https://stackoverflow.com/questions/28457925/how-to-download-a-file-with-progress-with-idhttp-via-https }
{ }
{ Fixed and adapted to Lazarus and Delphi by Giovani Da Cruz }
{ }
{ Please visit: https://showdelphi.com.br }
{----------------------------------------------------------------------}
unit util.download;
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;
{ Compatibilidade com lazarus }
{$IFDEF FPC}
OnWork := @HTTPWork;
OnWorkBegin := @HTTPWorkBegin;
OnWorkEnd := @HTTPWorkEnd;
{$ELSE}
OnWork := HTTPWork;
OnWorkBegin := HTTPWorkBegin;
OnWorkEnd := HTTPWorkEnd;
{$ENDIF}
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
{ Evento interno responsável por informar o progresso atual }
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.SetOnChange(const Value: TNotifyEvent);
begin
FOnChange := Value;
end;
procedure TIdHTTPProgress.SetProgress(const Value: Integer);
begin
FProgress := Value;
if Assigned(FOnChange) then
FOnChange(Self);
end;
end. |
{ }
{ TIdHTTPProgress - Extendend TIdHTTP to show progress download }
{ }
{ Creted in https://stackoverflow.com/questions/28457925/how-to-download-a-file-with-progress-with-idhttp-via-https }
{ }
{ Fixed and adapted to Lazarus and Delphi by Giovani Da Cruz }
{ }
{ Please visit: https://showdelphi.com.br }
{----------------------------------------------------------------------}
unit util.download;
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;
{ Compatibilidade com lazarus }
{$IFDEF FPC}
OnWork := @HTTPWork;
OnWorkBegin := @HTTPWorkBegin;
OnWorkEnd := @HTTPWorkEnd;
{$ELSE}
OnWork := HTTPWork;
OnWorkBegin := HTTPWorkBegin;
OnWorkEnd := HTTPWorkEnd;
{$ENDIF}
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
{ Evento interno responsável por informar o progresso atual }
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.SetOnChange(const Value: TNotifyEvent);
begin
FOnChange := Value;
end;
procedure TIdHTTPProgress.SetProgress(const Value: Integer);
begin
FProgress := Value;
if Assigned(FOnChange) then
FOnChange(Self);
end;
end.
Note que o código fonte acima já está ajustado para poder ser utilizado tanto em Delphi quanto em Lazarus.
Show de bola! Agora que já temos a nossa nova classe, vamos precisar utiliza-la.
Para isso vamos ao exemplo de um botão de download em um formulário.
Vamos ao exemplo de como baixar monitorando o progresso!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| { Botão que efetua o download }
procedure TForm1.bDownloadClick(Sender: TObject);
var
IdHTTPProgress : TIdHTTPProgress;
begin
IdHTTPProgress := TIdHTTPProgress.Create(Self);
try
{$IFDEF FPC}
IdHTTPProgress.OnChange := @ProgressOnChange;
IdHTTPProgress.OnWorkEnd := @WorkEnd;
{$ELSE}
IdHTTPProgress.OnChange := ProgressOnChange;
IdHTTPProgress.OnWorkEnd := WorkEnd;
{$ENDIF}
IdHTTPProgress.DownloadFile(edURL.Text, edFile.Text + edArq.Text);
finally
FreeAndNil(IdHTTPProgress);
end;
end; |
{ Botão que efetua o download }
procedure TForm1.bDownloadClick(Sender: TObject);
var
IdHTTPProgress : TIdHTTPProgress;
begin
IdHTTPProgress := TIdHTTPProgress.Create(Self);
try
{$IFDEF FPC}
IdHTTPProgress.OnChange := @ProgressOnChange;
IdHTTPProgress.OnWorkEnd := @WorkEnd;
{$ELSE}
IdHTTPProgress.OnChange := ProgressOnChange;
IdHTTPProgress.OnWorkEnd := WorkEnd;
{$ENDIF}
IdHTTPProgress.DownloadFile(edURL.Text, edFile.Text + edArq.Text);
finally
FreeAndNil(IdHTTPProgress);
end;
end;
Mas só isso? Sim é realmente só isso, mas repare que no exemplo acima estou setando dois eventos para o objeto: “ProgressOnChange” e “WorkEnd”. Estes são os eventos que fazem a atualização da barra de progresso e que avisam quando o download foi concluído.
Então vamos aos códigos dos eventos:
Primeiro do evento para monitorar o progresso:
1
2
| ProgressBar1.Position := TIdHTTPProgress(Sender).Progress;
Application.ProcessMessages; |
ProgressBar1.Position := TIdHTTPProgress(Sender).Progress;
Application.ProcessMessages;
Agora o evento que avisa quando o download foi concluído.
1
2
3
4
5
| procedure TForm1.WorkEnd(ASender: TObject; AWorkMode: TWorkMode);
begin
ProgressBar1.Position := 100;
ShowMessage('Concluído!');
end; |
procedure TForm1.WorkEnd(ASender: TObject; AWorkMode: TWorkMode);
begin
ProgressBar1.Position := 100;
ShowMessage('Concluído!');
end;
Pronto, temos tudo para baixar arquivos com monitoramento do andamento do processo!
Para ajudar no entendimento, assista o vídeo abaixo que explica o código deste post.
Também deixamos a unit em um repositório no Github: https://github.com/infussolucoes/IDHttpProgress
Certo pessoal, espero que tenham gostado, lembrando que para dúvidas ou sugestões, utilizem os comentários.
Um abraço e até a próxima. Valeu!
-
Giovani Da Cruz
-
8.401 views
- 2 comentários
- 22 de setembro de 2019
Está gostando do conteúdo? Considere pagar um cafezinho para nossa equipe!
Posts Relacionados - Continue Aprendendo
Tentei repeti todos os passos.Tentei compilar dá erro!?
Addicionei o IdComponent, continuo a não conseguir!?
O que perdi
Qual erro que você está tendo Mário?