如何在异步更新进度时成功地将 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);
并且它将我的流完全复制到我之前设置的位置。
我一直在尝试在下载或上传时更新我的下载预付百分比,上传完全没有问题,它完美运行。 但是当我尝试下载文件并尝试在等待它结束时更新进度百分比时,一旦我结束下载,我就会将 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);
并且它将我的流完全复制到我之前设置的位置。