CloudBlockBlob 的 OpenReadAsync 和 DownloadFromStreamAsync 函数之间的区别

Difference between OpenReadAsync and DownloadFromStreamAsync functions of CloudBlockBlob

Azure blob 存储中 CloudBlockBlobOpenReadAsyncDownloadToStreamAsync 函数有什么区别?在 google 中搜索但找不到答案。

OpenReadAsync returns a Task<Stream> 并且您将它与 await 一起使用。

样本测试方法

CloudBlobContainer container = GetRandomContainerReference();
            try
            {
                await container.CreateAsync();

                CloudBlockBlob blob = container.GetBlockBlobReference("blob1");
                using (MemoryStream wholeBlob = new MemoryStream(buffer))
                {
                    await blob.UploadFromStreamAsync(wholeBlob);
                }

                using (MemoryStream wholeBlob = new MemoryStream(buffer))
                {
                    using (var blobStream = await blob.OpenReadAsync())
                    {
                        await TestHelper.AssertStreamsAreEqualAsync(wholeBlob, blobStream);
                    }
                }
            }

DownloadToStreamAsync 是一个返回任务并以流对象作为输入的虚拟(可以重写)方法。

用法示例。

await blog.DownloadToStreamAsync(memoryStream);

OpenReadAsync 和 DownloadToStreamAsync 都可以为您启动异步操作来检索 blob 流。 根据我的测试,您可以通过以下部分更好地理解它们:

基本概念

DownloadToStreamAsync:启动异步操作以将 blob 的内容下载到流。

OpenReadAsync:发起一个异步操作,将blob的内容下载到流中。

用法

a) DownloadToStreamAsync

示例代码:

using (var fs = new FileStream(<yourLocalFilePath>, FileMode.Create))
{
    await blob.DownloadToStreamAsync(fs);
}

b) OpenReadAsync

示例代码:

//Set buffer for reading from a blob stream, the default value is 4MB.
blob.StreamMinimumReadSizeInBytes=10*1024*1024; //10MB
using (var blobStream = await blob.OpenReadAsync())
{
    using (var fs = new FileStream(localFile, FileMode.Create))
    {   
       await blobStream.CopyToAsync(fs);
    }
}

通过 Fiddler 捕获网络请求

a) DownloadToStreamAsync

b) OpenReadAsync

根据以上所述,DownloadToStreamAsync 仅发送一个获取 blob 流的 get 请求,而 OpenReadAsync 根据您设置的“Blob.StreamMinimumReadSizeInBytes”或默认值发送多个请求来获取 blob 流。

DownloadToStreamAsyncOpenReadAsync 的区别在于 DownloadToStreamAsync 会在 returning 之前将 blob 的内容下载到流中,但是 OpenReadAsync在流被消耗之前不会触发下载。

例如,如果将此用于 return 来自 ASP.NET 核心服务的文件流,您应该使用 OpenReadAsync 而不是 DownloadToStreamAsync:

带有 DownloadToStreamAsync 的示例(在这种情况下不推荐):

Stream target = new MemoryStream(); // Could be FileStream
await blob.DownloadToStreamAsync(target); // Returns when streaming (downloading) is finished. This requires the whole blob to be kept in memory before returning!
_logger.Log(LogLevel.Debug, $"DownloadToStreamAsync: Length: {target.Length} Position: {target.Position}"); // Output: DownloadToStreamAsync: Length: 517000 Position: 517000
target.Position = 0; // Rewind before returning Stream:
return File(target, contentType: blob.Properties.ContentType, fileDownloadName: blob.Name, lastModified: blob.Properties.LastModified, entityTag: null);

示例OpenReadAsync(在这种情况下推荐):

// Do NOT put the stream in a using (or close it), as this will close the stream before ASP.NET finish consuming it.
Stream blobStream = await blob.OpenReadAsync(); // Returns when the stream has been opened
_logger.Log(LogLevel.Debug, $"OpenReadAsync: Length: {blobStream.Length} Position: {blobStream.Position}"); // Output: OpenReadAsync: Length: 517000 Position: 0
return File(blobStream, contentType: blob.Properties.ContentType, fileDownloadName: blob.Name, lastModified: blob.Properties.LastModified, entityTag: null);

Microsoft Azure 会员 (here) 的回答:

The difference between DownloadStreamingAsync and OpenReadAsync is that the former gives you a network stream (wrapped with few layers but effectively think about it as network stream) which holds on to single connection, the later on the other hand fetches payload in chunks and buffers issuing multiple requests to fetch content. Picking one over the other one depends on the scenario, i.e. if the consuming code is fast and you have good broad network link to storage account then former might be better choice as you avoid multiple req-res exchanges but if the consumer is slow then later might be a good idea as it releases a connection back to the pool right after reading and buffering next chunk. We recommend to perf test your app with both to reveal which is best choice if it's not obvious.