带进度条的多个异步下载 [英] Multiple asynchronous download with progress bar

查看:27
本文介绍了带进度条的多个异步下载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从我的网络服务器下载文件夹,我想在进度条上显示下载的数据量/要下载的数据总量.首先,我尝试使用 WebClient.DownloadFile.它完美无缺,但没有触发 DownloadProgressChangedEventHandler.我猜它只能通过异步下载激活.所以我将我的方法改写为 WebClient.DownloadFileAsync.这就是它变得复杂的地方.

I'm trying to download folder from my web server and I want to display progress on progress bar with how many data was downloaded / total to download. First I've tried to use WebClient.DownloadFile. Which worked flawlessly, but it didn't trigger DownloadProgressChangedEventHandler. I guess it's activated only by async downloading. So I've rework my method to WebClient.DownloadFileAsync. This is where it gets complicated.

例如,我的 Web 服务器上有 30 个文件,大小为 53 MB.我想下载所有 30 个文件并在进度条上显示下载进度(并在它下面显示带有 xx/53 MB 下载的标签).

For example, I have 30 files on my web server with size 53 MB. I want to download all 30 files and show on progress bar what the progress of downloading (and under it show label with xx/53 MB download).

//Inicialized by opening dialog
private void DownloadForm_Shown(object sender, EventArgs e) {
   WebClient client = new WebClient();
   client.DownloadProgressChanged += client_DownloadProgressChanged;
   client.DownloadFileCompleted += client_DownloadFileCompleted;
   startDownload();
}

void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) {
    progressBar.Value = e.ProgressPercentage;
    labelProgress.Text = String.Format("Downloaded {0} of {1} bytes", e.BytesReceived, e.TotalBytesToReceive);
}

private void startDownload() {
   //files contains all URL links
   foreach (string str in files) {
      string urlDownload = HttpUtility.UrlPathEncode(str);
      //location is variable where file will be stored
      client.DownloadFileAsync(new Uri(urlDownload), location);

      //without this, async download will go crazy and wont download anything
      while (client.IsBusy) { }
   }
}

我有这个代码,发生的事情是它会开始下载,但不会更新进度条,也不会更新标签.然后下载后它会在大约 0.5 秒内更新进度和标签,就是这样.我是这类事情的初学者,你能帮我找出错误吗?我知道如何为一个文件制作进度条.但是我必须做些什么才能为多个文件制作它?

I have this code and what's happening is that it will start downloading but it won't update progress bar, nor the label. And then after downloading it will update progress and label in about 0.5sec and that's it. I'm beginner in these kind of things, could you please help me find an error? I know how to make progress bar for ONE file. But what I have to do, to make it for multiple files?

可以在此处找到包含一些解决方案的完整代码:http://pastebin.com/Hu4CCY8M但是调用 downloadURLs() 方法后 UI 会冻结.完成此方法后,它将重新开始工作.

Full code with some solution can be found here: http://pastebin.com/Hu4CCY8M But the UI will freeze after calling downloadURLs() method. And it will start working again after finishing this method.

推荐答案

没有一个好的最小、完整和可验证的代码示例可靠地重现问题,不可能完全解决问题.也就是说,从您发布的代码中可以清楚地看出,此处的主要错误在于您阻止了 UI 线程,从而防止在下载过程中对进度条所做的任何更改都反映在用户界面上.

Without a good Minimal, Complete, and Verifiable code example that reliably reproduces the problem, it's impossible to address the issue completely. That said, it's clear from the code you posted that the main thing wrong here is that you've blocked the UI thread, preventing any changes to the progress bar from being reflected on the user interface while the downloads are in progress.

疯狂"并不是一个精确的问题描述,甚至不是一个准确的描述.也就是说,我希望尝试同时开始所有下载会导致 WebClient 对象抛出一个异常,类似于 WebClient 不支持并发 I/O 操作".如果您希望(也许您应该希望)同时下载文件,您需要有多个 WebClient 对象,每个并发下载一个.

"Go crazy" isn't a precise problem description, or even close to one. That said, I would expect that trying to start all of the downloads concurrently to cause the WebClient object to throw an exception along the lines of "WebClient does not support concurrent I/O operations". If you want (and perhaps you should want) to download files concurrently, you'll need to have multiple WebClient objects, one for each concurrent download.

鉴于您一次下载一个文件的明显意图,您需要在不阻塞 UI 线程的情况下执行此操作.您发布的代码甚至不可能是原始代码的完全复制/粘贴,因为您在 startDownload() 方法中使用了标识符 client 而没有声明它任何地方,并且它可能与 DownloadForm_Shown() 方法中的局部变量 client 相同.因此,暂时忽略这种差异,以下是您发布的代码的变体,名义上可以解决您的问题:

Given your apparent intent to download the files one at a time, you need to do so without blocking the UI thread. The code you posted couldn't possibly be even an exact copy/paste from your original code, because you use the identifier client in the startDownload() method without it being declared anywhere, and without it possibly being the same as the local variable client in the DownloadForm_Shown() method. So, ignoring that discrepancy for the moment, here's a variation on the code you posted that will nominally address your issue:

private TaskCompletionSource<bool> _tcs;

private async void DownloadForm_Shown(object sender, EventArgs e) {
   WebClient client = new WebClient();
   client.DownloadProgressChanged += client_DownloadProgressChanged;
   client.DownloadFileCompleted += client_DownloadFileCompleted;
   await startDownload(client);
}

void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e) {
    progressBar.Value = e.ProgressPercentage;
    labelProgress.Text = String.Format("Downloaded {0} of {1} bytes", e.BytesReceived, e.TotalBytesToReceive);
}

void client_DownloadFileCompleted(object sender, DownloadFileCompletedEventArgs e) {
    // whatever else you have in this event handler, and then...
    _tcs.SetResult(true);
}

private async Task startDownload(WebClient client) {
   //files contains all URL links
   foreach (string str in files) {
      string urlDownload = HttpUtility.UrlPathEncode(str);
      //location is variable where file will be stored
      _tcs = new TaskCompletionSource<bool>();
      client.DownloadFileAsync(new Uri(urlDownload), location);
      await _tcs.Task;
   }
   _tcs = null; 
}

这样,DownloadForm_Shown() 方法将在下载过程中将控制权交还给 UI 线程.每个下载的文件完成后,将在 startDownload() 方法中恢复执行,以便开始下一个.

This way, the DownloadForm_Shown() method will yield control back to the UI thread while a download is progressing. Execution will resume back in the startDownload() method after each downloaded file has completed, so that the next can be started.

如果以上内容不能让您重回正轨,请改进问题,使其包含良好的 MCVE 和更准确的问题描述.

If the above does not get you back on track, please improve the question so that it includes a good MCVE and a more precise problem description.

这篇关于带进度条的多个异步下载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆