如何在异步更新进度时成功地将 blob 流复制到文件或文件流。?

How can I successfully copy a blob stream to a file or filestream while updating progress asynchronously.?

我一直在尝试在下载或上传时更新我的​​下载预付百分比,上传完全没有问题,它完美运行。 但是当我尝试下载文件并尝试在等待它结束时更新进度百分比时,一旦我结束下载,我就会将 mediaStream 复制到 Filestream,结果总是得到一个空文件:0Kb.

一开始我以为我的服务器端代码有问题,这是生成我的 SasToken、文件名和 Uri 的代码。

但如果我使用 blobStorage.DownloadToStreamAsync(fileStream) 它工作正常 如果我使用该方法,结果是一个文件以正确的扩展名存储在我想要的位置。

所以这是我的测试代码:

private async Task ExecuteDownloadFileCommand()
    {
        var busyView = new Busy();
        busyView.IsBusy = true;
        Busy.SetBusy(busyView.IsBusy, $"Please Wait...\nDownloading: {FileProgress * 100}");
        try
        {
            // Get the SAS token from the backend
            ICloudService cloudService = ServiceLocator.Instance.Resolve<ICloudService>();
            var storageToken = await cloudService.GetSasTokenAsync("7ec0d415c1994082a954ae6329b02915");

            // Use the SAS token to get a reference to the blob storage
            var storageUri = new Uri($"{storageToken.Uri}{storageToken.SasToken}");
            var blobStorage = new CloudBlockBlob(storageUri);

            //Organize the store file process.
            var storageFolder = await StorageFolder.GetFolderFromPathAsync(ApplicationData.Current.TemporaryFolder.Path);
            var savePicker = new Windows.Storage.Pickers.FileSavePicker();
            savePicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.PicturesLibrary;
            savePicker.FileTypeChoices.Add("Picture", new List<string> { ".jpg" });
            savePicker.SuggestedFileName = "photo.jpg";
            var storageDestinationFile = await savePicker.PickSaveFileAsync();
            FileStream fileStream = null;
            await Task.Run(() =>
            {
                fileStream = File.Create(storageDestinationFile.Path);
            });

            //await blobStorage.DownloadToStreamAsync(fileStream); //this line of code gives me the result i want.
            using (var mediaStream = await blobStorage.OpenReadAsync())
            {
                var bytesInBlocks = 1024;
                var mediaLength = mediaStream.Length;
                byte[] buffer = new byte[bytesInBlocks];
                var bytesRead = 0;
                double totalBytesRead = 0.0;
                var blocksRead = 0;
                var blockIds = new List<string>();

                IsDownloadingFile = true;
                FileProgress = 0.0;

                // Do what you need to for opening your output file
                do
                {
                    bytesRead = await mediaStream.ReadAsync(buffer, 0, bytesInBlocks);

                    if (bytesRead > 0)
                    {
                        //Update the interval counters
                        totalBytesRead += bytesRead;
                        blocksRead++;

                        //Update the progress bar.
                        var progress = totalBytesRead / mediaLength;
                        FileProgress = progress;
                        Busy.SetBusy(busyView.IsBusy, $"Please Wait... \nDownloading: {FileProgress * 100}");
                    }
                } while (bytesRead > 0);
                mediaStream.CopyTo(fileStream); //this line of code isnt copying anything.                   
                //using (var mediaRandomAccessStream = mediaStream.AsRandomAccessStream())
                //{
                //    using (var mediaInputStream = mediaRandomAccessStream.GetInputStreamAt(0)) //this line of code throws and exception because the randomaccess code cant be clone.
                //    {
                //        using (var destinationStream = await storageDestinationFile.OpenAsync(FileAccessMode.ReadWrite))
                //        {
                //            using (var destinationOutputStream = destinationStream.GetOutputStreamAt(0))
                //            {
                //                await RandomAccessStream.CopyAndCloseAsync(mediaRandomAccessStream, destinationOutputStream);
                //            }
                //        }
                //    }
                //}                    
            }
            fileStream.Dispose();
        }
        catch (Exception ex)
        {
            Debug.WriteLine($"[TaskListViewModel] Downloading error: {ex.Message}");
        }
        finally
        {
            busyView.IsBusy = false;
            IsDownloadingFile = false;
            FileProgress = 0.0;
            Busy.SetBusy(busyView.IsBusy);
        }
    }

现在我在使用 UWP,我也在使用模板 10,它促进了我在 UWP 中的开发,我想要的只是能够完全下载一个文件,同时向我的最终用户显示下载进度。

但是我好像还没有做到。

希望有人能指出我正确的方向。

事实证明,我需要做的就是像这样移动到流的开头:

 mediaStream.Seek(0, SeekOrigin.Begin);
 await mediaStream.CopyToAsync(fileStream);

并且它将我的流完全复制到我之前设置的位置。