带进度值的异步下载算法
Asynchronous download algorithm with progress value
我为我的 WinRT 应用制作了简单的算法。拥有 class 网络响应流。我需要使用 "ProgressChanged" 事件异步下载文件。这是我的方法:
public async void DownloadFileAsync(string uri, StorageFile path)
{
var request = WebRequest.CreateHttp(uri);
var response = await request.GetResponseAsync();
if (response != null)
{
long totalBytes = response.ContentLength;
long writedBytes = 0;
using(var webStream = response.GetResponseStream())
using (IRandomAccessStream stream = await path.OpenAsync(FileAccessMode.ReadWrite))
using (DataWriter dataWriter = new DataWriter(stream))
{
await Task.Run(() =>
{
int b;
while ((b = webStream.ReadByte()) != -1)
{
dataWriter.WriteByte((byte)b);
writedBytes++;
if (writedBytes % (totalBytes / 100) == 0)
OnProgressChanged(new ProgressEventArgs(writedBytes / (totalBytes / 100)));
}
});
await dataWriter.StoreAsync();
OnDownloadComplete(new EventArgs());
}
}
}
ProgressEventArgs 代码:
public class ProgressEventArgs : EventArgs
{
public ProgressEventArgs(double percentage)
{
Percentage = percentage;
}
public double Percentage { get; set; }
}
这是有效的。但我认为它应该更快。顺序字节读取太慢。我怎样才能让它更快。我是初学者。请帮忙
逐字节读取和写入大量数据可能会减慢您的速度,下载一个 1MB 的文件将调用数百万次方法。您应该使用缓冲区来读取块中的数据:
...
long totalBytesRead = 0;
// Allocate a 4KB buffer for each read/write
byte[] buffer = new byte[4 * 1024];
int bytesRead;
// Read up to 4KB of data, check if any data read
while ((bytesRead = webStream.Read(buffer, 0, buffer.Length)) > 0) {
// Write the 4KB (or less) buffer
dataWriter.WriteBuffer(buffer.AsBuffer(0, bytesRead));
totalBytesRead += bytesRead;
// TODO: Report progresss
}
....
最佳缓冲区大小取决于很多因素,4KB 的缓冲区应该没问题。 Here您可以获得更多信息。
我查看了您的代码,发现您读取字节的方式可能会导致下载速度变慢,我建议您使用 BackgroundDownloader class,因为它速度更快并且可以处理大量资源,例如视频、音乐和图片。
我做了个demo,希望对你有帮助。
Xaml 部分:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Button Content="Download File" Click="DownloadFile"/>
</Grid>
隐藏代码:
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private async void DownloadFile(object sender, RoutedEventArgs e)
{
try
{
Uri source = new Uri("http://h.hiphotos.baidu.com/zhidao/pic/item/6d81800a19d8bc3ed69473cb848ba61ea8d34516.jpg");
string destination = "dog.jpg";
StorageFile destinationFile = await KnownFolders.PicturesLibrary.CreateFileAsync(
destination, CreationCollisionOption.GenerateUniqueName);
BackgroundDownloader downloader = new BackgroundDownloader();
DownloadOperation download = downloader.CreateDownload(source, destinationFile);
await download.StartAsync();
// Attach progress and completion handlers.
//HandleDownloadAsync(download, true);
BackgroundDownloadProgress currentProgress = download.Progress;
double percent = 100;
if (currentProgress.TotalBytesToReceive > 0)
{
percent = currentProgress.BytesReceived * 100 / currentProgress.TotalBytesToReceive;
}
}
catch (Exception ex)
{
// LogException("Download Error", ex);
}
}
}
我已经测试过它并且有效。您也可以参考official sample了解更多信息。
此致
我为我的 WinRT 应用制作了简单的算法。拥有 class 网络响应流。我需要使用 "ProgressChanged" 事件异步下载文件。这是我的方法:
public async void DownloadFileAsync(string uri, StorageFile path)
{
var request = WebRequest.CreateHttp(uri);
var response = await request.GetResponseAsync();
if (response != null)
{
long totalBytes = response.ContentLength;
long writedBytes = 0;
using(var webStream = response.GetResponseStream())
using (IRandomAccessStream stream = await path.OpenAsync(FileAccessMode.ReadWrite))
using (DataWriter dataWriter = new DataWriter(stream))
{
await Task.Run(() =>
{
int b;
while ((b = webStream.ReadByte()) != -1)
{
dataWriter.WriteByte((byte)b);
writedBytes++;
if (writedBytes % (totalBytes / 100) == 0)
OnProgressChanged(new ProgressEventArgs(writedBytes / (totalBytes / 100)));
}
});
await dataWriter.StoreAsync();
OnDownloadComplete(new EventArgs());
}
}
}
ProgressEventArgs 代码:
public class ProgressEventArgs : EventArgs
{
public ProgressEventArgs(double percentage)
{
Percentage = percentage;
}
public double Percentage { get; set; }
}
这是有效的。但我认为它应该更快。顺序字节读取太慢。我怎样才能让它更快。我是初学者。请帮忙
逐字节读取和写入大量数据可能会减慢您的速度,下载一个 1MB 的文件将调用数百万次方法。您应该使用缓冲区来读取块中的数据:
...
long totalBytesRead = 0;
// Allocate a 4KB buffer for each read/write
byte[] buffer = new byte[4 * 1024];
int bytesRead;
// Read up to 4KB of data, check if any data read
while ((bytesRead = webStream.Read(buffer, 0, buffer.Length)) > 0) {
// Write the 4KB (or less) buffer
dataWriter.WriteBuffer(buffer.AsBuffer(0, bytesRead));
totalBytesRead += bytesRead;
// TODO: Report progresss
}
....
最佳缓冲区大小取决于很多因素,4KB 的缓冲区应该没问题。 Here您可以获得更多信息。
我查看了您的代码,发现您读取字节的方式可能会导致下载速度变慢,我建议您使用 BackgroundDownloader class,因为它速度更快并且可以处理大量资源,例如视频、音乐和图片。
我做了个demo,希望对你有帮助。
Xaml 部分:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Button Content="Download File" Click="DownloadFile"/>
</Grid>
隐藏代码:
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private async void DownloadFile(object sender, RoutedEventArgs e)
{
try
{
Uri source = new Uri("http://h.hiphotos.baidu.com/zhidao/pic/item/6d81800a19d8bc3ed69473cb848ba61ea8d34516.jpg");
string destination = "dog.jpg";
StorageFile destinationFile = await KnownFolders.PicturesLibrary.CreateFileAsync(
destination, CreationCollisionOption.GenerateUniqueName);
BackgroundDownloader downloader = new BackgroundDownloader();
DownloadOperation download = downloader.CreateDownload(source, destinationFile);
await download.StartAsync();
// Attach progress and completion handlers.
//HandleDownloadAsync(download, true);
BackgroundDownloadProgress currentProgress = download.Progress;
double percent = 100;
if (currentProgress.TotalBytesToReceive > 0)
{
percent = currentProgress.BytesReceived * 100 / currentProgress.TotalBytesToReceive;
}
}
catch (Exception ex)
{
// LogException("Download Error", ex);
}
}
}
我已经测试过它并且有效。您也可以参考official sample了解更多信息。
此致