Sample code for 30+ languages & platforms
PureBasic

Upload File in Blocks (with Content-MD5 header) and Commit the Block List

See more Azure Cloud Storage Examples

Demonstrates how to upload a file in blocks and then commit the block list. This example includes a Content-MD5 header for each block.

Chilkat PureBasic Downloads

PureBasic
IncludeFile "CkBinData.pb"
IncludeFile "CkFileAccess.pb"
IncludeFile "CkXml.pb"
IncludeFile "CkCrypt2.pb"
IncludeFile "CkAuthAzureStorage.pb"
IncludeFile "CkRest.pb"
IncludeFile "CkStringBuilder.pb"

Procedure ChilkatExample()

    success.i = 0

    ; Azure Blob Service Example: Upload a file in blocks, and then commit the block list.
    ; See also: https://msdn.microsoft.com/en-us/library/azure/dd135726.aspx

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

    rest.i = CkRest::ckCreate()
    If rest.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    ; Connect to the Azure Storage Blob Service
    bTls.i = 1
    port.i = 443
    bAutoReconnect.i = 1
    ; In this example, the storage account name is "chilkat".
    success = CkRest::ckConnect(rest,"chilkat.blob.core.windows.net",port,bTls,bAutoReconnect)
    If success <> 1
        Debug CkRest::ckLastErrorText(rest)
        CkRest::ckDispose(rest)
        ProcedureReturn
    EndIf

    ; Provide Azure Cloud credentials for the REST call.
    azAuth.i = CkAuthAzureStorage::ckCreate()
    If azAuth.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkAuthAzureStorage::setCkAccessKey(azAuth, "AZURE_ACCESS_KEY")
    ; The account name used here should match the 1st part of the domain passed in the call to Connect (above).
    CkAuthAzureStorage::setCkAccount(azAuth, "chilkat")
    CkAuthAzureStorage::setCkScheme(azAuth, "SharedKey")
    CkAuthAzureStorage::setCkService(azAuth, "Blob")
    ; This causes the "x-ms-version: 2021-08-06" header to be automatically added.
    CkAuthAzureStorage::setCkXMsVersion(azAuth, "2021-08-06")
    success = CkRest::ckSetAuthAzureStorage(rest,azAuth)

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

    ; As the blocks are uploaded, we'll keep an XML block list for the subsequent commit..
    xml.i = CkXml::ckCreate()
    If xml.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkXml::setCkTag(xml, "BlockList")

    ; Any type of file can be uploaded in this way.  It can a text file, binary file, anything...
    ; This example will upload an XML file that is approximately 275K in size.  It can be downloaded
    ; at http://www.chilkatsoft.com/hamlet.xml
    fac.i = CkFileAccess::ckCreate()
    If fac.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    success = CkFileAccess::ckOpenForRead(fac,"qa_data/xml/hamlet.xml")
    ; Assuming success for the example..

    ; We'll upload in 16K blocks (normally a program would upload in larger block sizes than this,
    ; but this is just an example...)
    blockSize.i = 16384

    ; How many 16K blocks?  (Including 1 for the last partial block)
    numBlocks.i = CkFileAccess::ckGetNumBlocks(fac,blockSize)

    crypt.i = CkCrypt2::ckCreate()
    If crypt.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    CkCrypt2::setCkHashAlgorithm(crypt, "md5")

    sbResponseBody.i = CkStringBuilder::ckCreate()
    If sbResponseBody.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    uriPath.i = CkStringBuilder::ckCreate()
    If uriPath.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    blockId.s
    dataBlock.i = CkBinData::ckCreate()
    If dataBlock.i = 0
        Debug "Failed to create object."
        ProcedureReturn
    EndIf

    contentMd5.s
    i.i = 0
    While i < numBlocks

        CkBinData::ckClear(dataBlock)
        success = CkFileAccess::ckReadBlockBd(fac,i,blockSize,dataBlock)
        If success = 0
            Debug CkFileAccess::ckLastErrorText(fac)
            CkRest::ckDispose(rest)
            CkAuthAzureStorage::ckDispose(azAuth)
            CkXml::ckDispose(xml)
            CkFileAccess::ckDispose(fac)
            CkCrypt2::ckDispose(crypt)
            CkStringBuilder::ckDispose(sbResponseBody)
            CkStringBuilder::ckDispose(uriPath)
            CkBinData::ckDispose(dataBlock)
            ProcedureReturn
        EndIf

        ; Generate a base64 block ID.  
        ; (Chilkat provides a helper method named GenBlockId to make this easy)
        ; A pre-base64 encoded block ID length of 4 is sufficient in this case because
        ; this file certainly won't have more than 99,999 blocks..
        blockId = CkFileAccess::ckGenBlockId(fac,i,4,"base64")

        ; Add this blockId to the list of blocks to be committed.
        CkXml::ckNewChild2(xml,"Latest",blockId)

        ; Build the URI path
        CkStringBuilder::ckClear(uriPath)
        success = CkStringBuilder::ckAppend(uriPath,"/mycontainer/hamlet.xml?comp=block&blockId=")
        success = CkStringBuilder::ckAppend(uriPath,blockId)

        contentMd5 = CkCrypt2::ckHashBdENC(crypt,dataBlock)
        CkRest::ckAddHeader(rest,"Content-MD5",contentMd5)

        ; Upload this block..
        CkStringBuilder::ckClear(sbResponseBody)
        success = CkRest::ckFullRequestBd(rest,"PUT",CkStringBuilder::ckGetAsString(uriPath),dataBlock,sbResponseBody)
        If success = 0
            Debug CkRest::ckLastErrorText(rest)
            CkRest::ckDispose(rest)
            CkAuthAzureStorage::ckDispose(azAuth)
            CkXml::ckDispose(xml)
            CkFileAccess::ckDispose(fac)
            CkCrypt2::ckDispose(crypt)
            CkStringBuilder::ckDispose(sbResponseBody)
            CkStringBuilder::ckDispose(uriPath)
            CkBinData::ckDispose(dataBlock)
            ProcedureReturn
        EndIf

        ; Verify that we received a 201 status code.
        If CkRest::ckResponseStatusCode(rest) <> 201
            ; Examine the request/response to see what happened.
            Debug "response status code = " + Str(CkRest::ckResponseStatusCode(rest))
            Debug "response status text = " + CkRest::ckResponseStatusText(rest)
            Debug "response header: " + CkRest::ckResponseHeader(rest)
            Debug "response body (if any): " + CkStringBuilder::ckGetAsString(sbResponseBody)
            Debug "---"
            Debug "LastRequestStartLine: " + CkRest::ckLastRequestStartLine(rest)
            Debug "LastRequestHeader: " + CkRest::ckLastRequestHeader(rest)
            CkRest::ckDispose(rest)
            CkAuthAzureStorage::ckDispose(azAuth)
            CkXml::ckDispose(xml)
            CkFileAccess::ckDispose(fac)
            CkCrypt2::ckDispose(crypt)
            CkStringBuilder::ckDispose(sbResponseBody)
            CkStringBuilder::ckDispose(uriPath)
            CkBinData::ckDispose(dataBlock)
            ProcedureReturn
        EndIf

        i = i + 1
    Wend

    CkFileAccess::ckFileClose(fac)

    ; Now commit the blocks.
    ; Let's have a look at the XML that will commit the blocks:
    xmlStr.s = CkXml::ckGetXml(xml)
    Debug xmlStr

    ; The XML will look like this:

    ; <?xml version="1.0" encoding="utf-8" ?>
    ; <BlockList>
    ;     <Latest>MDAwMA==</Latest>
    ;     <Latest>MDAwMQ==</Latest>
    ;     <Latest>MDAwMg==</Latest>
    ;     <Latest>MDAwMw==</Latest>
    ;     <Latest>MDAwNA==</Latest>
    ;     <Latest>MDAwNQ==</Latest>
    ;     <Latest>MDAwNg==</Latest>
    ;     <Latest>MDAwNw==</Latest>
    ;     <Latest>MDAwOA==</Latest>
    ;     <Latest>MDAwOQ==</Latest>
    ;     <Latest>MDAxMA==</Latest>
    ;     <Latest>MDAxMQ==</Latest>
    ;     <Latest>MDAxMg==</Latest>
    ;     <Latest>MDAxMw==</Latest>
    ;     <Latest>MDAxNA==</Latest>
    ;     <Latest>MDAxNQ==</Latest>
    ;     <Latest>MDAxNg==</Latest>
    ;     <Latest>MDAxNw==</Latest>
    ; </BlockList>

    ; --------------------------------------------------------------------------
    ; IMPORTANT: Remove the Content-MD5 header previously set in the loop above.
    ; --------------------------------------------------------------------------
    CkRest::ckRemoveHeader(rest,"Content-MD5")

    ; Send the PUT Block List...
    responseStr.s = CkRest::ckFullRequestString(rest,"PUT","/mycontainer/hamlet.xml?comp=blocklist",xmlStr)
    If CkRest::ckLastMethodSuccess(rest) <> 1
        Debug CkRest::ckLastErrorText(rest)
        CkRest::ckDispose(rest)
        CkAuthAzureStorage::ckDispose(azAuth)
        CkXml::ckDispose(xml)
        CkFileAccess::ckDispose(fac)
        CkCrypt2::ckDispose(crypt)
        CkStringBuilder::ckDispose(sbResponseBody)
        CkStringBuilder::ckDispose(uriPath)
        CkBinData::ckDispose(dataBlock)
        ProcedureReturn
    EndIf

    ; When successful, the Azure Storage service will respond with a 201 response status code,
    ; with no response body.

    If CkRest::ckResponseStatusCode(rest) <> 201
        ; Examine the request/response to see what happened.
        Debug "response status code = " + Str(CkRest::ckResponseStatusCode(rest))
        Debug "response status text = " + CkRest::ckResponseStatusText(rest)
        Debug "response header: " + CkRest::ckResponseHeader(rest)
        Debug "response body (if any): " + responseStr
        Debug "---"
        Debug "LastRequestStartLine: " + CkRest::ckLastRequestStartLine(rest)
        Debug "LastRequestHeader: " + CkRest::ckLastRequestHeader(rest)
        CkRest::ckDispose(rest)
        CkAuthAzureStorage::ckDispose(azAuth)
        CkXml::ckDispose(xml)
        CkFileAccess::ckDispose(fac)
        CkCrypt2::ckDispose(crypt)
        CkStringBuilder::ckDispose(sbResponseBody)
        CkStringBuilder::ckDispose(uriPath)
        CkBinData::ckDispose(dataBlock)
        ProcedureReturn
    EndIf

    Debug "Success."


    CkRest::ckDispose(rest)
    CkAuthAzureStorage::ckDispose(azAuth)
    CkXml::ckDispose(xml)
    CkFileAccess::ckDispose(fac)
    CkCrypt2::ckDispose(crypt)
    CkStringBuilder::ckDispose(sbResponseBody)
    CkStringBuilder::ckDispose(uriPath)
    CkBinData::ckDispose(dataBlock)


    ProcedureReturn
EndProcedure