首页 文章

azure blob存储异步下载,带进度条

提问于
浏览
1

我试图获得一个完整的示例,使用连接到进度条的.DownloadToStreamAsync()方法从Azure Blob存储下载文件 .

我发现了对azure存储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.DownloadToStream Async (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),我有时会得到'无法写入文件在另一个进程错误中打开...'并且进程失败..

1 回答

  • 1

    使用你的代码:

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

    无法显示进度,因为仅在下载完成时代码才会出现此功能 . DownloadToStream 函数将在内部拆分块中的大blob并下载块 .

    您需要做的是使用您的代码下载这些块 . 你要做的是使用 DownloadRangeToStream 方法 . 一段时间我回答了一个类似的问题,你可能会觉得有用:Azure download blob part .

相关问题