带进度值的异步下载算法

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了解更多信息。

此致