diff --git a/documentation/Microsoft Azure Storage Client Library for C++ 2.0.0.md b/documentation/Microsoft Azure Storage Client Library for C++ 2.0.0.md index b6431e14..581f0321 100644 --- a/documentation/Microsoft Azure Storage Client Library for C++ 2.0.0.md +++ b/documentation/Microsoft Azure Storage Client Library for C++ 2.0.0.md @@ -1,8 +1,8 @@ -#Azure Storage Client Library for C++ 2.0.0: What’s new and sample code +# Azure Storage Client Library for C++ 2.0.0: What’s new and sample code This article introduces the changes in Microsoft Azure Storage Client Library for C++ 2.0.0 and provides some code samples. You can also check the GitHub [readme.md](https://github.com/Azure/azure-storage-cpp/blob/master/README.md) and [changelog.log](https://github.com/Azure/azure-storage-cpp/blob/master/Changelog.txt) files for more details. -##New storage blob type +## New storage blob type By default, Azure Storage Client Library for C++ 2.0.0 uses REST API version 2015-2-21. This version of the Azure Storage service includes several important features that you can find at [2015-2 version blog link]. The C++ client library supports one key feature, the new storage blob type called *Append Blob*. @@ -10,98 +10,127 @@ Append Blob is optimized for fast append operations, making it ideal for scenari The following sample code shows the use of Append Blob. +```c++ +#include +#include +#include +#include +#include + +int main() +{ + // Define the connection-string with your values. + const utility::string_t storage_connection_string(U("DefaultEndpointsProtocol=https;AccountName=;AccountKey=;EndpointSuffix=core.windows.net")); + try - { - // Initialize Storage account - azure::storage::cloud_storage_account storage_account = azure::storage::cloud_storage_account::parse(storage_connection_string); - - // Create a blob container - azure::storage::cloud_blob_client blob_client = storage_account.create_cloud_blob_client(); - azure::storage::cloud_blob_container container = blob_client.get_container_reference(U("my-sample-container")); - - // Return value is true if the container did not exist and was successfully created - container.create_if_not_exists(); - - // Create Append Blob - azure::storage::cloud_append_blob append_blob = container.get_append_blob_reference(U("my-append-1")); - append_blob.properties().set_content_type(U("text/plain; charset=utf-8")); - append_blob.create_or_replace(); - - // Append blocks in different ways: - // 1. Append one block - concurrency::streams::istream append_input_stream1 = concurrency::streams::bytestream::open_istream(utility::conversions::to_utf8string(U("block text."))); - append_blob.append_block(append_input_stream1, utility::string_t()); - append_input_stream1.close().wait(); - // 2. Append from stream - concurrency::streams::istream append_input_stream2 = concurrency::streams::bytestream::open_istream(utility::conversions::to_utf8string(U("stream text."))); - append_blob.append_from_stream(append_input_stream2); - append_input_stream2.close().wait(); - - // 3. Append from text - append_blob.append_text(U("more text.")); - - // Download Append Blob as text - utility::string_t append_text = append_blob.download_text(); - ucout << U("Append Text: ") << append_text << std::endl; - - // Delete the blob - append_blob.delete_blob(); - - // Delete the blob container - container.delete_container_if_exists(); - } - catch (const azure::storage::storage_exception& e) - { - ucout << U("Error: ") << e.what() << std::endl; - - azure::storage::request_result result = e.result(); - azure::storage::storage_extended_error extended_error = result.extended_error(); - if (!extended_error.message().empty()) - { - ucout << extended_error.message() << std::endl; - } - } - catch (const std::exception& e) - { - ucout << U("Error: ") << e.what() << std::endl; - } - -##Range-based for-loop to list objects + { + // Initialize Storage account + azure::storage::cloud_storage_account storage_account = azure::storage::cloud_storage_account::parse(storage_connection_string); + + // Create a blob container + azure::storage::cloud_blob_client blob_client = storage_account.create_cloud_blob_client(); + azure::storage::cloud_blob_container container = blob_client.get_container_reference(U("my-sample-container")); + + // Return value is true if the container did not exist and was successfully created + container.create_if_not_exists(); + + // Create Append Blob + azure::storage::cloud_append_blob append_blob = container.get_append_blob_reference(U("my-append-1")); + append_blob.properties().set_content_type(U("text/plain; charset=utf-8")); + append_blob.create_or_replace(); + + // Append blocks in different ways: + // 1. Append one block + concurrency::streams::istream append_input_stream1 = concurrency::streams::bytestream::open_istream(utility::conversions::to_utf8string(U("block text."))); + append_blob.append_block(append_input_stream1, utility::string_t()); + append_input_stream1.close().wait(); + + // 2. Append from stream + concurrency::streams::istream append_input_stream2 = concurrency::streams::bytestream::open_istream(utility::conversions::to_utf8string(U("stream text."))); + append_blob.append_from_stream(append_input_stream2); + append_input_stream2.close().wait(); + + // 3. Append from text + append_blob.append_text(U("more text.")); + + // 4. Append from raw buffer + char str[] = "buffer text."; + uint8_t* buffer = (uint8_t*)str; + concurrency::streams::istream buffer_input_stream = concurrency::streams::rawptr_stream::open_istream(buffer, sizeof(str) - 1); + append_blob.append_from_stream(buffer_input_stream); + buffer_input_stream.close().wait(); + + // Download Append Blob as text + utility::string_t append_text = append_blob.download_text(); + ucout << U("Append Text: ") << append_text << std::endl; + + // Delete the blob + append_blob.delete_blob(); + + // Delete the blob container + container.delete_container_if_exists(); + } + catch (const azure::storage::storage_exception& e) + { + ucout << U("Error: ") << e.what() << std::endl; + + azure::storage::request_result result = e.result(); + azure::storage::storage_extended_error extended_error = result.extended_error(); + if (!extended_error.message().empty()) + { + ucout << extended_error.message() << std::endl; + } + } + catch (const std::exception& e) + { + ucout << U("Error: ") << e.what() << std::endl; + } + return 0; +} +``` + +Note: Both `append_block` and `append_from_stream` takes `concurrency::streams::istream`, however, append block is a strict one-to-one mapping for [Append Block REST API](https://docs.microsoft.com/en-us/rest/api/storageservices/append-block), that has the limitation of 4MB in size, while `append_from_stream` does not. Also, using append block, user can track that the MD5 value of the given block of data is valid. `append_from_stream` internally calls `append_block` to upload data. + +## Range-based for-loop to list objects For versions earlier than 2.0.0, you can list blobs via the following method. - // List blobs in the blob container - azure::storage::list_blob_item_iterator end_of_results; - for (auto it = container.list_blobs(); it != end_of_results; ++it) - { - if (it->is_blob()) - { - process_blob(it->as_blob()); - } - else - { - process_directory(it->as_directory()); - } - } +```c++ +// List blobs in the blob container +azure::storage::list_blob_item_iterator end_of_results; +for (auto it = container.list_blobs(); it != end_of_results; ++it) +{ + if (it->is_blob()) + { + process_blob(it->as_blob()); + } + else + { + process_directory(it->as_directory()); + } +} +``` With version 2.0.0, you can also use a range-based for-loop to list blobs. - // List blobs in the blob container - for (auto& item : container.list_blobs()) - { - if (item.is_blob()) - { - process_blob(item.as_blob()); - } - else - { - process_directory(item.as_directory()); - } - } +```c++ +// List blobs in the blob container +for (auto& item : container.list_blobs()) +{ + if (item.is_blob()) + { + process_blob(item.as_blob()); + } + else + { + process_directory(item.as_directory()); + } +} +``` For more details about listing APIs of the C++ client library, visit [Efficiently use Listing APIs in Microsoft Azure Storage Client Library for C++](https://azure.microsoft.com/documentation/articles/storage-c-plus-plus-enumeration/). -##Handling query parameters in the resource URI +## Handling query parameters in the resource URI With versions earlier than 2.0.0, the C++ client library will *keep* only the following parameters and ignore the others when handling the Azure Storage resource URI: @@ -211,30 +240,35 @@ With version 2.0.0, the C++ client library will ignore only the following parame As a result of this change, you can write code like this: - azure::storage::storage_uri sas_uri( - web::http::uri(U("https://myaccount.queue.core.windows.net/myqueue?sp=raup&sv=2012-02-12&se=2013-05-14T18%3A23%3A15Z&st=2013-05-14T17%3A23%3A15Z&sig=mysignature")), - web::http::uri(U("https://myaccount-secondary.queue.core.windows.net/myqueue?sp=raup&sv=2012-02-12&se=2013-05-14T18%3A23%3A15Z&st=2013-05-14T17%3A23%3A15Z&sig=mysignature"))); - azure::storage::cloud_queue queue2(sas_uri); +```c++ +azure::storage::storage_uri sas_uri( + web::http::uri(U("https://myaccount.queue.core.windows.net/myqueue?sp=raup&sv=2012-02-12&se=2013-05-14T18%3A23%3A15Z&st=2013-05-14T17%3A23%3A15Z&sig=mysignature")), + web::http::uri(U("https://myaccount-secondary.queue.core.windows.net/myqueue?sp=raup&sv=2012-02-12&se=2013-05-14T18%3A23%3A15Z&st=2013-05-14T17%3A23%3A15Z&sig=mysignature"))); +azure::storage::cloud_queue queue2(sas_uri); +``` Note that with this behavior change, the C++ client library will throw an `std::invalid_argument` error if multiple sources identified the same parameter. For example, the C++ client library will report an error if you try to specify *sas_credentials* with `azure::storage::storage_credentials` and the SAS URI at the same time, as shown in the following code. - utility::string_t sas_token(U("sv=2012-02-12&st=2013-05-14T17%3A23%3A15Z&se=2013-05-14T18%3A23%3A15Z&sp=raup&sig=mysignature")); - azure::storage::storage_credentials sas_credentials(sas_token); - azure::storage::storage_uri sas_uri( - web::http::uri(U("https://myaccount.queue.core.windows.net/myqueue?sp=raup&sv=2012-02-12&se=2013-05-14T18%3A23%3A15Z&st=2013-05-14T17%3A23%3A15Z&sig=mysignature")), - web::http::uri(U("https://myaccount-secondary.queue.core.windows.net/myqueue?sp=raup&sv=2012-02-12&se=2013-05-14T18%3A23%3A15Z&st=2013-05-14T17%3A23%3A15Z&sig=mysignature"))); - azure::storage::cloud_queue queue2(sas_uri, sas_credentials); +```c++ +utility::string_t sas_token(U("sv=2012-02-12&st=2013-05-14T17%3A23%3A15Z&se=2013-05-14T18%3A23%3A15Z&sp=raup&sig=mysignature")); +azure::storage::storage_credentials sas_credentials(sas_token); +azure::storage::storage_uri sas_uri( + web::http::uri(U("https://myaccount.queue.core.windows.net/myqueue?sp=raup&sv=2012-02-12&se=2013-05-14T18%3A23%3A15Z&st=2013-05-14T17%3A23%3A15Z&sig=mysignature")), + web::http::uri(U("https://myaccount-secondary.queue.core.windows.net/myqueue?sp=raup&sv=2012-02-12&se=2013-05-14T18%3A23%3A15Z&st=2013-05-14T17%3A23%3A15Z&sig=mysignature"))); +azure::storage::cloud_queue queue2(sas_uri, sas_credentials); +``` -##Renamed interfaces +## Renamed interfaces Azure Storage Client Library for C++ 2.0.0 changes interfaces as follows: - Renames `cloud_blob::start_copy_from_blob` to `cloud_blob::start_copy` - Renames `cloud_blob::start_copy_from_blob_async` to `cloud_blob::start_copy_async` -##Bug fixes +## Bug fixes + You can find the bug fixes at [changelog.txt](https://github.com/Azure/azure-storage-cpp/blob/master/Changelog.txt). -##Next steps +## Next steps For more information about Azure Storage and the client library for C++, see the following resources: - [How to use Blob Storage from C++](http://azure.microsoft.com/documentation/articles/storage-c-plus-plus-how-to-use-blobs/)