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

S3 Upload the Parts for a Multipart Upload

See more Amazon S3 (new) Examples

This example uploads a large file in parts. The multipart upload needs to have been first initiated prior to uploading the parts.

See http://docs.aws.amazon.com/AmazonS3/latest/API/mpUploadUploadPart.html for more information about uploading parts.

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.AuthAws,
  Chilkat.FileAccess,
  Chilkat.Stream,
  Chilkat.StringBuilder,
  Chilkat.Xml,
  Chilkat.Rest;

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

procedure RunDemo;
var
  success: Boolean;
  xmlInit: TXml;
  uploadId: string;
  fileToUploadPath: string;
  partSize: Integer;
  fac: TFileAccess;
  numParts: Integer;
  partsListFile: string;
  partsListXml: TXml;
  rest: TRest;
  bTls: Boolean;
  port: Integer;
  bAutoReconnect: Boolean;
  authAws: TAuthAws;
  partNumber: Integer;
  sbPartNumber: TStringBuilder;
  bPartAlreadyUploaded: Boolean;
  numUploadedParts: Integer;
  xRec0: TXml;
  foundRec: TXml;
  fileStream: TStream;
  responseStr: string;
  etag: string;
  xPart: TXml;

begin
  success := False;

  //  In the 1st step for uploading a large file, the multipart upload was initiated
  //  as shown here: Initiate Multipart Upload

  //  Other S3 Multipart Upload Examples:
  //  Complete Multipart Upload
  //  Abort Multipart Upload
  //  List Parts

  //  When we initiated the multipart upload, we saved the XML response to a file.  This
  //  XML response contains the UploadId.  We'll begin by loading that XML and getting
  //  the Upload ID.

  xmlInit := TXml.Create;
  success := xmlInit.LoadXmlFile('s3_multipart_uploads/initiate.xml');
  if (success <> True) then
    begin
      WriteLn('Did not find the initiate.xml XML file.');
      Exit;
    end;

  uploadId := xmlInit.GetChildContent('UploadId');
  WriteLn('UploadId = ' + uploadId);

  //  When uploading parts, we need to keep an XML record of each part number
  //  and its corresponding ETag, which is received in the response for each part.
  //  There can be up to 10000 parts, numbered 1 to 10000.  
  //  After all parts have been uploaded, the final step will be to complete
  //  the multipart upload (see Complete Multipart Upload)

  //  In this example, the large file we want to upload is somethingBig.zip
  fileToUploadPath := 's3_multipart_uploads/somethingBig.zip';

  //  The minimum allowed part size is 5MB (5242880 bytes).  The last part can be smaller because
  //  it will contain the remainder of the file.  (This minimum is enforced by the AWS service.)
  //  We'll use the minimum allowed part size for this example.
  partSize := 5242880;

  //  Let's use Chilkat's FileAccess API to examine the file to be uploaded.  We'll get the size
  //  of the file and find out how many parts will be needed, including the final "partial" part.
  fac := TFileAccess.Create;
  fac.OpenForRead(fileToUploadPath);

  //  How many parts will there be if each part is 5242880 bytes?
  numParts := fac.GetNumBlocks(partSize);
  WriteLn('numParts = ' + numParts);
  fac.FileClose();

  //  Imagine that we may be running this for the 1st time, or maybe we already
  //  attempted to upload parts, and something failed. Maybe there was a network problem
  //  the resulted in not all parts getting uploaded.  We'll write this code so that if run again,
  //  it will upload whatever parts haven't yet been uploaded.

  //  We'll keep a partsList.xml file to record the parts that have already been successfully
  //  uploaded.  If this file does not yet exist, we'll create it..
  partsListFile := 's3_multipart_uploads/partsList.xml';
  partsListXml := TXml.Create;
  if (fac.FileExists(partsListFile) = True) then
    begin
      partsListXml.LoadXmlFile(partsListFile);
    end;
  //  Make sure the top-level tag is "CompleteMultipartUpload"
  partsListXml.Tag := 'CompleteMultipartUpload';

  //  --------------------------------------
  //  Before entering the loop to upload parts,
  //  setup the REST object with AWS authentication,
  //  and make the initial connection.
  rest := TRest.Create;

  //  Connect to the Amazon AWS REST server.
  bTls := True;
  port := 443;
  bAutoReconnect := True;
  success := rest.Connect('s3.amazonaws.com',port,bTls,bAutoReconnect);

  //  ----------------------------------------------------------------------------
  //  Important: For buckets created in regions outside us-east-1,
  //  there are three important changes that need to be made.
  //  See Working with S3 Buckets in Non-us-east-1 Regions for the details.
  //  ----------------------------------------------------------------------------

  //  Provide AWS credentials for the REST call.
  authAws := TAuthAws.Create;
  authAws.AccessKey := 'AWS_ACCESS_KEY';
  authAws.SecretKey := 'AWS_SECRET_KEY';
  authAws.ServiceName := 's3';
  success := rest.SetAuthAws(authAws);

  //  Set the bucket name via the HOST header.
  //  In this case, the bucket name is "chilkat100".
  rest.Host := 'chilkat100.s3.amazonaws.com';
  //  --------------------------------------

  partNumber := 1;
  sbPartNumber := TStringBuilder.Create;

  while (partNumber <= numParts) do
    begin
      WriteLn('---- ' + partNumber + ' ----');

      //  This cumbersome way of converting an integer to a string is because
      //  Chilkat examples are written in a script that is converted to many programming languages.
      //  At this time, the translator does not have integer-to-string code generation capability..
      sbPartNumber.Clear();
      sbPartNumber.AppendInt(partNumber);

      bPartAlreadyUploaded := False;

      //  If there are no children, then the XML is empty and no parts have yet been uploaded.
      numUploadedParts := partsListXml.NumChildren;
      if (numUploadedParts > 0) then
        begin
          //  If some parts have been uploaded, check to see if this particular part was already upload.
          //  If so, then it can be skipped.

          //  Position ourselves at the 1st record.
          xRec0 := partsListXml.GetChild(0);
          foundRec := xRec0.FindNextRecord('PartNumber',sbPartNumber.GetAsString());
          if (xRec0.LastMethodSuccess = True) then
            begin
              bPartAlreadyUploaded := True;
              WriteLn('Part ' + partNumber + ' was previously uploaded.');
              WriteLn(foundRec.GetXml());
              foundRec.Free;
            end;

          xRec0.Free;
        end;

      //  If this part was not already uploaded, we need to upload.
      //  Also update the partsListXml and save as each part is successfully uploaded.
      if (bPartAlreadyUploaded = False) then
        begin
          WriteLn('Uploading part ' + partNumber + ' ...');

          //  Setup the stream source for the large file to be uploaded..
          fileStream := TStream.Create;
          fileStream.SourceFile := fileToUploadPath;
          //  The Chilkat Stream API has features to make uploading a parts
          //  of a file easy.  Indicate the part size by setting the SourceFilePartSize
          //  property.
          fileStream.SourceFilePartSize := partSize;

          //  Our HTTP start line to upload a part will look like this:
          //  PUT /ObjectName?partNumber=PartNumber&uploadId=UploadId HTTP/1.1

          //  Set the query params.  We'll need partNumber and uploadId.
          //  Make sure the query params from previous iterations are clear.
          rest.ClearAllQueryParams();
          rest.AddQueryParam('partNumber',sbPartNumber.GetAsString());
          rest.AddQueryParam('uploadId',uploadId);

          //  Upload this particular file part.
          //  Tell the fileStream which part is being uploaded.
          //  Our partNumber is 1-based (the 1st part is at index 1), but the fileStream's SourceFilePart
          //  property is 0-based.  Therefore we use partNumber-1.
          fileStream.SourceFilePart := partNumber - 1;

          //  Because the SourceFilePart and SourceFilePartSize properties are set, the stream will 
          //  will provide just that part of the file.  
          responseStr := rest.FullRequestStream('PUT','/somethingBig.zip',fileStream);
          if (rest.LastMethodSuccess <> True) then
            begin
              WriteLn(rest.LastErrorText);
              Exit;
            end;

          if (rest.ResponseStatusCode <> 200) 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: ' + responseStr);
              WriteLn('---');
              WriteLn('LastRequestStartLine: ' + rest.LastRequestStartLine);
              WriteLn('LastRequestHeader: ' + rest.LastRequestHeader);
              Exit;
            end;

          //  OK, this part was uploaded..
          //  The response will have a 0-length body.  The only information we need is the 
          //  ETag response header field.
          etag := rest.ResponseHdrByName('ETag');
          //  It should be present, but just in case there was no ETag header...
          if (rest.LastMethodSuccess <> True) then
            begin
              WriteLn('No ETag response header found!');
              WriteLn('response header: ' + rest.ResponseHeader);
              Exit;
            end;

          //  We need to add record to the partsListXml.
          //  The record will look like this:
          //  &lt;Part>
          //    &lt;PartNumber>PartNumber&lt;/PartNumber>
          //    &lt;ETag>ETag&lt;/ETag>
          //  &lt;/Part>
          xPart := partsListXml.NewChild('Part','');
          xPart.NewChildInt2('PartNumber',partNumber);
          xPart.NewChild2('ETag',etag);
          xPart.Free;

          success := partsListXml.SaveXml(partsListFile);
          if (success <> True) then
            begin
              WriteLn(partsListXml.LastErrorText);
              Exit;
            end;

          WriteLn('-- Part ' + partNumber + ' uploaded. ---------------------');
        end;

      partNumber := partNumber + 1;
    end;

  WriteLn('Finished.  All parts uploaded.');


  xmlInit.Free;
  fac.Free;
  partsListXml.Free;
  rest.Free;
  authAws.Free;
  sbPartNumber.Free;
          fileStream.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.