Sample code for 30+ languages & platforms
Pascal (Lazarus/Delphi)

Azure File Service: Upload Large File

See more Azure Cloud Storage Examples

Sample code to upload a large file to a directory in a share in the Azure File Service. A file is uploaded by first creating the file in the Azure share and then writing ranges of bytes to the file. Azure imposes a 4MB limit for each PUT to write a range. Files larger than 4MB need to be uploaded by making multiple "Put Range" calls. This example uploads a large file requiring multiple "Put Range" calls.

Chilkat Pascal (Lazarus/Delphi) Downloads

Pascal (Lazarus/Delphi)
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.FileAccess,
  Chilkat.Rest,
  Chilkat.AuthAzureStorage,
  Chilkat.BinData,
  Chilkat.StringBuilder;

// ---------------------------------------------------------------------------

procedure RunDemo;
var
  success: Boolean;
  rest: TRest;
  bTls: Boolean;
  port: Integer;
  bAutoReconnect: Boolean;
  localFilePath: string;
  fac: TFileAccess;
  szLocalFile: Integer;
  azAuth: TAuthAzureStorage;
  sbFileSize: TStringBuilder;
  responseStr: string;
  sbRange: TStringBuilder;
  sbResponseBody: TStringBuilder;
  bdFileData: TBinData;
  numBytesLeft: Integer;
  curIndex: Integer;
  chunkSize: Integer;

begin
  success := False;

  //  Azure File Service Example: Upload a large file.  
  //  See:  https://docs.microsoft.com/en-us/rest/api/storageservices/create-share
  //  also see: https://docs.microsoft.com/en-us/rest/api/storageservices/put-range

  //  This example requires the Chilkat API to have been previously unlocked.
  //  See Global Unlock Sample for sample code.

  rest := TRest.Create;

  //  Connect to the Azure Storage Blob Service
  bTls := True;
  port := 443;
  bAutoReconnect := True;
  //  In this example, the storage account name is "chilkat".
  success := rest.Connect('chilkat.file.core.windows.net',port,bTls,bAutoReconnect);
  if (success <> True) then
    begin
      WriteLn(rest.LastErrorText);
      Exit;
    end;

  //  This example will upload a larger file.
  localFilePath := 'qa_data/zips/somethingBig.zip';
  fac := TFileAccess.Create;
  //  Note: The FileSize method returns a signed 32-bit integer.  If the file is potentially larger than 2GB, call FileSizeStr instead to return
  //  the size of the file as a string, then convert to an integer value.
  szLocalFile := fac.FileSize(localFilePath);
  if (szLocalFile < 0) then
    begin
      WriteLn(fac.LastErrorText);
      Exit;
    end;

  //  Provide Azure Cloud credentials for the REST calls.
  azAuth := TAuthAzureStorage.Create;
  azAuth.AccessKey := 'AZURE_ACCESS_KEY';
  //  The account name used here should match the 1st part of the domain passed in the call to Connect (above).
  azAuth.Account := 'chilkat';
  azAuth.Scheme := 'SharedKey';
  azAuth.Service := 'File';
  //  This causes the "x-ms-version: 2021-08-06" header to be automatically added.
  azAuth.XMsVersion := '2021-08-06';
  success := rest.SetAuthAzureStorage(azAuth);

  //  Note: The application does not need to explicitly set the following
  //  headers: x-ms-date, Authorization.  These headers
  //  are automatically set by Chilkat.

  //  However, a few additional headers are required for the "Create File" operation:
  rest.AddHeader('x-ms-type','file');

  //  This required header specifies the final size of the file (or the maximum size it can be).
  sbFileSize := TStringBuilder.Create;
  sbFileSize.AppendInt(szLocalFile);
  rest.AddHeader('x-ms-content-length',sbFileSize.GetAsString());

  //  Send a PUT request to create the file (or replace the file if it already exists).
  //  This will initialize the file in the Azure file storage.  To upload content, we'll need
  //  to do the "Put Range" operation one or more times.

  //  The following will create the file "somethingBig.zip" in the share "pip"
  responseStr := rest.FullRequestNoBody('PUT','/pip/somethingBig.zip');
  if (rest.LastMethodSuccess <> True) then
    begin
      WriteLn(rest.LastErrorText);
      Exit;
    end;

  //  When successful, the Azure File Service will respond with a 201 (Created) response status code,
  //  with no XML response body.  If an error response is returned, there will be an XML response body.

  if (rest.ResponseStatusCode <> 201) then
    begin
      //  Examine the request/response to see what happened.
      WriteLn('response status code = ' + rest.ResponseStatusCode);
      WriteLn('response status text = ' + rest.ResponseStatusText);
      WriteLn('response header: ' + rest.ResponseHeader);
      WriteLn('response body (if any): ' + responseStr);
      WriteLn('---');
      WriteLn('LastRequestStartLine: ' + rest.LastRequestStartLine);
      WriteLn('LastRequestHeader: ' + rest.LastRequestHeader);
      Exit;
    end;

  WriteLn('Successfully created somethingBig.zip');

  //  --------------------------------------------------------------------------------
  //  Upload the file data...

  //  Make sure the headers from the "Create File" operation are removed.
  rest.ClearAllHeaders();

  //  The x-ms-write header is required for each "Put Range" request.
  rest.AddHeader('x-ms-write','update');

  sbRange := TStringBuilder.Create;
  sbResponseBody := TStringBuilder.Create;
  bdFileData := TBinData.Create;

  //  Open the file.  We'll be reading and uploading in chunks..
  success := fac.OpenForRead(localFilePath);
  if (success <> True) then
    begin
      WriteLn(fac.LastErrorText);
      Exit;
    end;

  numBytesLeft := szLocalFile;
  curIndex := 0;
  while numBytesLeft > 0 do
    begin

      chunkSize := numBytesLeft;
      //  Azure allows for 4MB max chunks  (4 x 1024 x 1024 = 4194304)
      if (chunkSize > 4194304) then
        begin
          chunkSize := 4194304;
        end;

      //  The only tricky part here is to correctly add the x-ms-range header.
      //  It will be formatted like this:
      //  x-ms-range: bytes=0-759623
      sbRange.Clear();
      sbRange.Append('bytes=');
      sbRange.AppendInt(curIndex);
      sbRange.Append('-');
      sbRange.AppendInt(curIndex + chunkSize - 1);

      //  This replaces the header if it already exists..
      rest.AddHeader('x-ms-range',sbRange.GetAsString());

      //  Read the next chunk from the local file.
      bdFileData.Clear();
      success := fac.FileReadBd(chunkSize,bdFileData);

      success := rest.FullRequestBd('PUT','/pip/somethingBig.zip?comp=range',bdFileData,sbResponseBody);
      if (success <> True) then
        begin
          //  This would indicate a failure where no response was received.
          WriteLn(rest.LastErrorText);
          Exit;
        end;

      //  A 201 response indicates the chunk was uploaded.
      if (rest.ResponseStatusCode <> 201) then
        begin
          //  Examine the request/response to see what happened.
          WriteLn('response status code = ' + rest.ResponseStatusCode);
          WriteLn('response status text = ' + rest.ResponseStatusText);
          WriteLn('response header: ' + rest.ResponseHeader);
          WriteLn('response body (if any): ' + responseStr);
          WriteLn('---');
          WriteLn('LastRequestStartLine: ' + rest.LastRequestStartLine);
          WriteLn('LastRequestHeader: ' + rest.LastRequestHeader);
          Exit;
        end;

      WriteLn('Uploaded chunk from ' + curIndex + ' to ' + curIndex + chunkSize - 1);

      curIndex := curIndex + chunkSize;
      numBytesLeft := numBytesLeft - chunkSize;
    end;

  fac.FileClose();

  WriteLn('success.');


  rest.Free;
  fac.Free;
  azAuth.Free;
  sbFileSize.Free;
  sbRange.Free;
  sbResponseBody.Free;
  bdFileData.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.