【问题标题】:azure blob storage async download with progress bar带有进度条的天蓝色 blob 存储异步下载
【发布时间】:2017-02-20 18:17:07
【问题描述】:

我正在尝试使用连接到进度条的 .DownloadToStreamAsync() 方法从 Azure Blob 存储下载文件的完整示例。

我找到了对 azure storage sdk 旧实现的引用,但它们不能与较新的 sdk(已实现这些异步方法)编译或不适用于当前的 nuget 包。

https://blogs.msdn.microsoft.com/avkashchauhan/2010/11/03/uploading-a-blob-to-azure-storage-with-progress-bar-and-variable-upload-block-size/

https://blogs.msdn.microsoft.com/kwill/2013/03/05/asynchronous-parallel-blob-transfers-with-progress-change-notification-2-0/

我是 .NET 中异步/等待线程的新手,想知道是否有人可以帮助我完成以下操作(在 Windows 窗体应用程序中)并展示我如何“挂钩”到文件下载...我看到一些示例不使用 .DownloadToStream 方法,而是下载 blob 文件的块。但我想知道,因为这些新的 ...Async() 方法存在于较新的 Storage SDK 中,如果有的话可以做一些更聪明的事情吗?

所以假设下面的工作(非异步),我还需要做什么才能使用 blockBlob.DownloadToStreamAsync(fileStream);方法,这甚至是正确的使用方法,我怎样才能得到进展?

理想情况下,我可以通过任何方式来挂钩 blob 下载的进度,这样我就可以在大下载时更新 Windows 窗体 UI。所以如果以下方法不正确,请赐教:)

// Retrieve storage account from connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
    CloudConfigurationManager.GetSetting("StorageConnectionString"));

// Create the blob client.
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();

// Retrieve reference to a previously created container.
CloudBlobContainer container = blobClient.GetContainerReference("mycontainer");

// Retrieve reference to a blob named "photo1.jpg".
CloudBlockBlob blockBlob = container.GetBlockBlobReference("photo1.jpg");

// Save blob contents to a file.
using (var fileStream = System.IO.File.OpenWrite(@"path\myfile"))
{
    blockBlob.DownloadToStream(fileStream);
}

使用Gaurav 建议的很棒的建议method(下载1mb 块),我已经实现了使用后台工作人员进行下载,这样我就可以随时更新UI。

do 循环中的主要部分将范围下载到流中,然后将流写入到我在原始示例中没有触及的文件系统,但我添加了代码来更新工作进程并监听工作进程取消(中止下载).. 不确定这是否是问题所在?

为了完整起见,下面是 worker_DoWork 方法中的所有内容:

public void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        object[] parameters = e.Argument as object[];
        string localFile = (string)parameters[0];
        string blobName = (string)parameters[1];
        string blobContainerName = (string)parameters[2];
        CloudBlobClient client = (CloudBlobClient)parameters[3];      

        try
        {
            int segmentSize = 1 * 1024 * 1024; //1 MB chunk
            var blobContainer = client.GetContainerReference(blobContainerName);
            var blob = blobContainer.GetBlockBlobReference(blobName);
            blob.FetchAttributes();
            blobLengthRemaining = blob.Properties.Length;
            blobLength = blob.Properties.Length;
            long startPosition = 0;
            do
            {
                long blockSize = Math.Min(segmentSize, blobLengthRemaining);
                byte[] blobContents = new byte[blockSize];
                using (MemoryStream ms = new MemoryStream())
                {
                    blob.DownloadRangeToStream(ms, startPosition, blockSize);
                    ms.Position = 0;
                    ms.Read(blobContents, 0, blobContents.Length);
                    using (FileStream fs = new FileStream(localFile, FileMode.OpenOrCreate))
                    {
                        fs.Position = startPosition;
                        fs.Write(blobContents, 0, blobContents.Length);
                    }
                }
                startPosition += blockSize;
                blobLengthRemaining -= blockSize;

                if (blobLength > 0)
                {
                    decimal totalSize = Convert.ToDecimal(blobLength);
                    decimal downloaded = totalSize - Convert.ToDecimal(blobLengthRemaining);
                    decimal blobPercent = (downloaded / totalSize) * 100;
                    worker.ReportProgress(Convert.ToInt32(blobPercent));
                }

                if (worker.CancellationPending)
                {
                    e.Cancel = true;
                    blobDownloadCancelled = true;
                    return;
                }
            }
            while (blobLengthRemaining > 0);
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }

这是可行的,但在更大的文件(例如 30mb)上,我有时会收到“无法写入文件,因为在另一个进程中打开错误......”并且进程失败..

【问题讨论】:

    标签: c# azure azure-blob-storage


    【解决方案1】:

    使用您的代码:

    using (var fileStream = System.IO.File.OpenWrite(@"path\myfile"))
    {
        blockBlob.DownloadToStream(fileStream);
    }
    

    无法显示进度,因为代码只有在下载完成时才会从这个函数中出来。 DownloadToStream 函数将在内部将一个大的 blob 分成块并下载这些块。

    您需要做的是使用您的代码下载这些块。你需要做的是使用DownloadRangeToStream 方法。不久前我回答了一个类似的问题,您可能会发现它很有用:Azure download blob part

    【讨论】:

    • 感谢您的确认.. 将使用您建议的块中下载示例并在 UI 的单独线程上运行,以便我可以从剩余字节等更新进度条。
    • 我已经在后台工作人员上实现了这一点,并且一切都运行良好.. 几乎.. 在一些更大的文件上,有时会出现进程错误“无法写入文件作为在另一个进程中打开”错误...'这可能是在尝试再次写入之前写入文件系统的延迟吗?
    • 如果不查看您的代码,就无法判断您收到错误的原因。您介意分享您的最新代码吗?
    • 是的,没问题..我是新来的..最好粘贴另一个答案,以便代码可读/语法突出显示,还是我将其发布在 cmets 中。
    • 最好的方法是更新您的问题并包含您在那里使用的代码。或者,您可以使用 pastebin 或 Github Gist 之类的东西并在评论中分享链接。将此信息放在 cmets 中不是一个好主意 :)。 HTH。
    猜你喜欢
    • 2022-08-02
    • 1970-01-01
    • 2022-01-08
    • 2015-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-11
    相关资源
    最近更新 更多