Created
September 2, 2021 06:36
-
-
Save chgeuer/d2d5d214783b67f9c23a3b53ea96363c to your computer and use it in GitHub Desktop.
A gazillion ways to download a blob
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.IO; | |
using System.Threading.Tasks; | |
using Azure; | |
using Azure.Storage.Blobs; | |
using Azure.Storage.Blobs.Models; | |
static class Program | |
{ | |
// https://github.com/Azure/azure-sdk-for-net/issues/22022 | |
static async Task Main(string[] args) | |
{ | |
BlobClient b = new(new($"https://typora.blob.core.windows.net/typoraimages/2021/09/02/06/34/2021-08-30--08-48-47----74FZ3X4H2A2TK2Y5T2Z4XA06YC.png")); | |
var algos = new (string, Func<BlobClient, Task<byte[]>>)[] { | |
(nameof(DownloadStreamingAsync), DownloadStreamingAsync), | |
(nameof(DownloadAsync), DownloadAsync), | |
(nameof(DownloadToAsync), DownloadToAsync), | |
(nameof(DownloadContentAsync), DownloadContentAsync), | |
(nameof(OpenReadAsync), OpenReadAsync) | |
}; | |
foreach ((var name, var algo) in algos) | |
{ | |
var buffer = await algo(b); | |
Console.Error.WriteLine($"{name}: {buffer.Length}"); | |
} | |
} | |
public static async Task<byte[]> DownloadStreamingAsync(this BlobClient blobClient) | |
{ | |
// DownloadStreamingAsync gives you a network stream (wrapped with few layers but effectively think about it as network stream) | |
// which holds on to single connection. | |
// Use to access network stream directly for any advanced scenario | |
Response<BlobDownloadStreamingResult> response = await blobClient.DownloadStreamingAsync(); | |
BlobDownloadStreamingResult value = response.Value; | |
Stream content = value.Content; | |
MemoryStream ms = new(); | |
await content.CopyToAsync(ms); | |
return ms.ToArray(); | |
} | |
public static async Task<byte[]> DownloadAsync(this BlobClient blobClient) | |
{ | |
// DownloadAsync() has been deprecated. | |
BlobDownloadInfo value = (await blobClient.DownloadAsync()).Value; | |
Stream content = value.Content; | |
bool doItEasy = true; | |
if (doItEasy) | |
{ | |
MemoryStream ms = new(); | |
await content.CopyToAsync(ms); | |
return ms.ToArray(); | |
} | |
else | |
{ | |
int contentLength = (int)value.ContentLength; | |
byte[] buffer = new byte[contentLength]; | |
int current = 0; | |
int read = await content.ReadAsync(buffer.AsMemory(current, (int)value.ContentLength - current)); | |
while (read > 0) | |
{ | |
current += read; | |
read = await content.ReadAsync(buffer.AsMemory(current, (int)value.ContentLength - current)); | |
} | |
return buffer; | |
} | |
} | |
public static async Task<byte[]> DownloadToAsync(this BlobClient blobClient) | |
{ | |
// This copies the blob into a stream, however, the SDK sets an | |
// "x-ms-range: bytes=0-268435455", i.e. only fetches the first 256 MB, | |
// no matter how large the blob is?!? | |
MemoryStream ms = new(); | |
_ = await blobClient.DownloadToAsync(ms); | |
return ms.ToArray(); | |
} | |
public static async Task<byte[]> DownloadContentAsync(this BlobClient blobClient) | |
{ | |
// DownloadContentAsync() for downloading small blobs that can fit into memory | |
BlobDownloadResult value = (await blobClient.DownloadContentAsync()).Value; | |
BinaryData content = value.Content; | |
return content.ToArray(); | |
} | |
public static async Task<byte[]> OpenReadAsync(this BlobClient blobClient) | |
{ | |
// OpenReadAsync fetches payload in chunks and buffers issuing multiple requests to fetch content. | |
const int chunkSize = 8 * 1024 * 1024; // is 4MB by default | |
Stream stream = await blobClient.OpenReadAsync(options: new (allowModifications: true) { BufferSize = chunkSize }); | |
MemoryStream ms = new(); | |
await stream.CopyToAsync(ms); | |
return ms.ToArray(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment