Delphi DLL
Delphi DLL
HTTP Download in Parallel with Simultaneous Range Requests
See more HTTP Examples
Demonstrates how to download a large file with parallel simultaneous requests, where each request downloads a segment (range) of the remote file.Chilkat Delphi DLL Downloads
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Http, StringBuilder, Task, HttpResponse, FileAccess;
...
procedure TForm1.Button1Click(Sender: TObject);
var
success: Boolean;
http: HCkHttp;
url: PWideChar;
resp: HCkHttpResponse;
remoteFileSize: Integer;
chunkSize: Integer;
http1: HCkHttp;
http2: HCkHttp;
http3: HCkHttp;
http4: HCkHttp;
sbRange: HCkStringBuilder;
numReplaced: Integer;
task1: HCkTask;
task2: HCkTask;
task3: HCkTask;
task4: HCkTask;
numLive: Integer;
numErrors: Integer;
fac: HCkFileAccess;
bSame: Boolean;
begin
success := False;
// This requires the Chilkat API to have been previously unlocked.
// See Global Unlock Sample for sample code.
http := CkHttp_Create();
// First get the size of the file to be downloaded.
url := 'https://www.chilkatsoft.com/hamlet.xml';
resp := CkHttpResponse_Create();
success := CkHttp_HttpNoBody(http,'HEAD',url,resp);
if (success = False) then
begin
Memo1.Lines.Add(CkHttp__lastErrorText(http));
Exit;
end;
remoteFileSize := CkHttpResponse_getContentLength(resp);
Memo1.Lines.Add('Downloading ' + IntToStr(remoteFileSize) + ' bytes...');
// Let's download in 4 chunks.
// (the last chunk will be whatever remains after the 1st 3 equal sized chunks)
chunkSize := remoteFileSize / 4;
// The Range header is used to download a range from a resource
// Range: bytes=<range-start>-<range-end>
// or
// Range: bytes=<range-start>-
// We're writing code this way for clarity..
http1 := CkHttp_Create();
http2 := CkHttp_Create();
http3 := CkHttp_Create();
http4 := CkHttp_Create();
sbRange := CkStringBuilder_Create();
CkStringBuilder_SetString(sbRange,'bytes=<range-start>-<range-end>');
numReplaced := CkStringBuilder_ReplaceI(sbRange,'<range-start>',0);
numReplaced := CkStringBuilder_ReplaceI(sbRange,'<range-end>',chunkSize - 1);
Memo1.Lines.Add(CkStringBuilder__getAsString(sbRange));
CkHttp_SetRequestHeader(http1,'Range',CkStringBuilder__getAsString(sbRange));
CkStringBuilder_SetString(sbRange,'bytes=<range-start>-<range-end>');
numReplaced := CkStringBuilder_ReplaceI(sbRange,'<range-start>',chunkSize);
numReplaced := CkStringBuilder_ReplaceI(sbRange,'<range-end>',2 * chunkSize - 1);
Memo1.Lines.Add(CkStringBuilder__getAsString(sbRange));
CkHttp_SetRequestHeader(http2,'Range',CkStringBuilder__getAsString(sbRange));
CkStringBuilder_SetString(sbRange,'bytes=<range-start>-<range-end>');
numReplaced := CkStringBuilder_ReplaceI(sbRange,'<range-start>',2 * chunkSize);
numReplaced := CkStringBuilder_ReplaceI(sbRange,'<range-end>',3 * chunkSize - 1);
Memo1.Lines.Add(CkStringBuilder__getAsString(sbRange));
CkHttp_SetRequestHeader(http3,'Range',CkStringBuilder__getAsString(sbRange));
CkStringBuilder_SetString(sbRange,'bytes=<range-start>-');
numReplaced := CkStringBuilder_ReplaceI(sbRange,'<range-start>',3 * chunkSize);
Memo1.Lines.Add(CkStringBuilder__getAsString(sbRange));
CkHttp_SetRequestHeader(http4,'Range',CkStringBuilder__getAsString(sbRange));
// Start each range download
task1 := CkHttp_DownloadAsync(http1,url,'qa_output/chunk1.dat');
CkTask_Run(task1);
task2 := CkHttp_DownloadAsync(http2,url,'qa_output/chunk2.dat');
CkTask_Run(task2);
task3 := CkHttp_DownloadAsync(http3,url,'qa_output/chunk3.dat');
CkTask_Run(task3);
task4 := CkHttp_DownloadAsync(http4,url,'qa_output/chunk4.dat');
CkTask_Run(task4);
// Wait for the downloads to complete.
numLive := 4;
while numLive > 0 do
begin
numLive := 0;
if (CkTask_getLive(task1) = True) then
begin
numLive := numLive + 1;
end;
if (CkTask_getLive(task2) = True) then
begin
numLive := numLive + 1;
end;
if (CkTask_getLive(task3) = True) then
begin
numLive := numLive + 1;
end;
if (CkTask_getLive(task4) = True) then
begin
numLive := numLive + 1;
end;
if (numLive > 0) then
begin
// SleepMs is a convenience method to cause the caller to sleep for N millisec.
// It does not cause the given task to sleep..
CkTask_SleepMs(task1,10);
end;
end;
// All should be downloaded now..
// Examine the result of each Download.
numErrors := 0;
if (CkTask_GetResultBool(task1) = False) then
begin
Memo1.Lines.Add(CkTask__resultErrorText(task1));
numErrors := numErrors + 1;
end;
if (CkTask_GetResultBool(task2) = False) then
begin
Memo1.Lines.Add(CkTask__resultErrorText(task2));
numErrors := numErrors + 1;
end;
if (CkTask_GetResultBool(task3) = False) then
begin
Memo1.Lines.Add(CkTask__resultErrorText(task3));
numErrors := numErrors + 1;
end;
if (CkTask_GetResultBool(task4) = False) then
begin
Memo1.Lines.Add(CkTask__resultErrorText(task4));
numErrors := numErrors + 1;
end;
if (numErrors > 0) then
begin
CkTask_Dispose(task1);
CkTask_Dispose(task2);
CkTask_Dispose(task3);
CkTask_Dispose(task4);
Exit;
end;
// All downloads were successful.
// Compose the file from the parts.
fac := CkFileAccess_Create();
success := CkFileAccess_ReassembleFile(fac,'qa_output','chunk','dat','qa_output/hamlet.xml');
if (success = False) then
begin
Memo1.Lines.Add(CkFileAccess__lastErrorText(fac));
end
else
begin
Memo1.Lines.Add('Success.');
end;
CkTask_Dispose(task1);
CkTask_Dispose(task2);
CkTask_Dispose(task3);
CkTask_Dispose(task4);
// Let's download in the regular way, and then compare files..
success := CkHttp_Download(http,url,'qa_output/hamletRegular.xml');
// Compare files.
bSame := CkFileAccess_FileContentsEqual(fac,'qa_output/hamlet.xml','qa_output/hamletRegular.xml');
Memo1.Lines.Add('bSame = ' + IntToStr(Ord(bSame)));
CkHttp_Dispose(http);
CkHttpResponse_Dispose(resp);
CkHttp_Dispose(http1);
CkHttp_Dispose(http2);
CkHttp_Dispose(http3);
CkHttp_Dispose(http4);
CkStringBuilder_Dispose(sbRange);
CkFileAccess_Dispose(fac);
end;