Pascal (Lazarus/Delphi)
Pascal (Lazarus/Delphi)
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 Pascal (Lazarus/Delphi) Downloads
program ChilkatDemo;
// Demonstrates using the Chilkat Pascal wrapper via the C bridge DLL.
// Builds as a console application under Lazarus (FPC) or Delphi.
{$IFDEF FPC}
{$MODE DELPHI}
{$ENDIF}
{$APPTYPE CONSOLE}
uses
{$IFDEF UNIX}
cthreads,
{$ENDIF}
SysUtils,
CkDllLoader,
Chilkat.Http,
Chilkat.StringBuilder,
Chilkat.Task,
Chilkat.HttpResponse,
Chilkat.FileAccess;
// ---------------------------------------------------------------------------
procedure RunDemo;
var
success: Boolean;
http: THttp;
url: string;
resp: THttpResponse;
remoteFileSize: Integer;
chunkSize: Integer;
http1: THttp;
http2: THttp;
http3: THttp;
http4: THttp;
sbRange: TStringBuilder;
numReplaced: Integer;
task1: TTask;
task2: TTask;
task3: TTask;
task4: TTask;
numLive: Integer;
numErrors: Integer;
fac: TFileAccess;
bSame: Boolean;
begin
success := False;
// This requires the Chilkat API to have been previously unlocked.
// See Global Unlock Sample for sample code.
http := THttp.Create;
// First get the size of the file to be downloaded.
url := 'https://www.chilkatsoft.com/hamlet.xml';
resp := THttpResponse.Create;
success := http.HttpNoBody('HEAD',url,resp);
if (success = False) then
begin
WriteLn(http.LastErrorText);
Exit;
end;
remoteFileSize := resp.ContentLength;
WriteLn('Downloading ' + 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 := THttp.Create;
http2 := THttp.Create;
http3 := THttp.Create;
http4 := THttp.Create;
sbRange := TStringBuilder.Create;
sbRange.SetString('bytes=<range-start>-<range-end>');
numReplaced := sbRange.ReplaceI('<range-start>',0);
numReplaced := sbRange.ReplaceI('<range-end>',chunkSize - 1);
WriteLn(sbRange.GetAsString());
http1.SetRequestHeader('Range',sbRange.GetAsString());
sbRange.SetString('bytes=<range-start>-<range-end>');
numReplaced := sbRange.ReplaceI('<range-start>',chunkSize);
numReplaced := sbRange.ReplaceI('<range-end>',2 * chunkSize - 1);
WriteLn(sbRange.GetAsString());
http2.SetRequestHeader('Range',sbRange.GetAsString());
sbRange.SetString('bytes=<range-start>-<range-end>');
numReplaced := sbRange.ReplaceI('<range-start>',2 * chunkSize);
numReplaced := sbRange.ReplaceI('<range-end>',3 * chunkSize - 1);
WriteLn(sbRange.GetAsString());
http3.SetRequestHeader('Range',sbRange.GetAsString());
sbRange.SetString('bytes=<range-start>-');
numReplaced := sbRange.ReplaceI('<range-start>',3 * chunkSize);
WriteLn(sbRange.GetAsString());
http4.SetRequestHeader('Range',sbRange.GetAsString());
// Start each range download
task1 := http1.DownloadAsync(url,'qa_output/chunk1.dat');
task1.Run();
task2 := http2.DownloadAsync(url,'qa_output/chunk2.dat');
task2.Run();
task3 := http3.DownloadAsync(url,'qa_output/chunk3.dat');
task3.Run();
task4 := http4.DownloadAsync(url,'qa_output/chunk4.dat');
task4.Run();
// Wait for the downloads to complete.
numLive := 4;
while numLive > 0 do
begin
numLive := 0;
if (task1.Live = True) then
begin
numLive := numLive + 1;
end;
if (task2.Live = True) then
begin
numLive := numLive + 1;
end;
if (task3.Live = True) then
begin
numLive := numLive + 1;
end;
if (task4.Live = 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..
task1.SleepMs(10);
end;
end;
// All should be downloaded now..
// Examine the result of each Download.
numErrors := 0;
if (task1.GetResultBool() = False) then
begin
WriteLn(task1.ResultErrorText);
numErrors := numErrors + 1;
end;
if (task2.GetResultBool() = False) then
begin
WriteLn(task2.ResultErrorText);
numErrors := numErrors + 1;
end;
if (task3.GetResultBool() = False) then
begin
WriteLn(task3.ResultErrorText);
numErrors := numErrors + 1;
end;
if (task4.GetResultBool() = False) then
begin
WriteLn(task4.ResultErrorText);
numErrors := numErrors + 1;
end;
if (numErrors > 0) then
begin
task1.Free;
task2.Free;
task3.Free;
task4.Free;
Exit;
end;
// All downloads were successful.
// Compose the file from the parts.
fac := TFileAccess.Create;
success := fac.ReassembleFile('qa_output','chunk','dat','qa_output/hamlet.xml');
if (success = False) then
begin
WriteLn(fac.LastErrorText);
end
else
begin
WriteLn('Success.');
end;
task1.Free;
task2.Free;
task3.Free;
task4.Free;
// Let's download in the regular way, and then compare files..
success := http.Download(url,'qa_output/hamletRegular.xml');
// Compare files.
bSame := fac.FileContentsEqual('qa_output/hamlet.xml','qa_output/hamletRegular.xml');
WriteLn('bSame = ' + bSame);
http.Free;
resp.Free;
http1.Free;
http2.Free;
http3.Free;
http4.Free;
sbRange.Free;
fac.Free;
end;
// ---------------------------------------------------------------------------
begin
try
RunDemo;
except
on E: Exception do
WriteLn('Unhandled exception: ', E.ClassName, ': ', E.Message);
end;
WriteLn;
{$IFDEF MSWINDOWS}
WriteLn('Press Enter to exit...');
ReadLn;
{$ENDIF}
end.