Is there a smarter way than a busy-wait to check for download completion of System.Net.WebClient.DownloadFileAsync()?
I'm downloading a file using System.Net.WebClient.DownloadFileAsync(). The only reason for using the async version is to show the progress of the download. My code execution may not continue before 100% have been reached. Currently I'm using a busy-wait (see code) but I wonder if there is a smarter way to do it.
using(WebClient oWebClient = new WebClient()开发者_开发知识库)
{
oWebClient.Encoding = System.Text.Encoding.UTF8;
long lReceived = 0;
long lTotal = 0;
// Set up a delegate to watch download progress.
oWebClient.DownloadProgressChanged += delegate(object sender, DownloadProgressChangedEventArgs e)
{
Console.WriteLine(e.ProgressPercentage + "% (" + e.BytesReceived / 1024f + "kb of " + e.TotalBytesToReceive / 1024f + "kb)");
// Assign to outer variables to allow busy-wait to check.
lReceived = e.BytesReceived;
lTotal = e.TotalBytesToReceive;
};
oWebClient.DownloadFileAsync(new Uri(sUrl + "?" + sPostData), sTempFile);
while(lReceived == 0 || lReceived != lTotal)
{
// Busy wait.
Thread.Sleep(1000);
}
}
using(WebClient oWebClient = new WebClient())
{
// use an event for waiting, rather than a Thread.Sleep() loop.
var notifier = new AutoResetEvent(false);
oWebClient.Encoding = System.Text.Encoding.UTF8;
long lReceived = 0;
long lTotal = 0;
// Set up a delegate to watch download progress.
oWebClient.DownloadProgressChanged += delegate(object sender, DownloadProgressChangedEventArgs e)
{
Console.WriteLine(e.ProgressPercentage + "% (" + e.BytesReceived / 1024f + "kb of " + e.TotalBytesToReceive / 1024f + "kb)");
// Assign to outer variables to allow busy-wait to check.
lReceived = e.BytesReceived;
lTotal = e.TotalBytesToReceive;
// Indicate that things are done
if(lReceived >= lTotal) notifier.Set();
};
oWebClient.DownloadFileAsync(new Uri(sUrl + "?" + sPostData), sTempFile);
// wait for signal to proceed
notifier.WaitOne();
}
Use an AutoResetEvent. Call its Set() method in a DownloadFileCompleted event handler, its WaitOne() method after the DownloadFileAsync() call.
using(WebClient oWebClient = new WebClient())
{
// use an event for waiting, rather than a Thread.Sleep() loop.
var notifier = new AutoResetEvent(false);
oWebClient.Encoding = System.Text.Encoding.UTF8;
long lReceived = 0;
long lTotal = 0;
// Set up a delegate to watch download progress.
oWebClient.DownloadProgressChanged += delegate(object sender, DownloadProgressChangedEventArgs e)
{
Console.WriteLine(e.ProgressPercentage + "% (" + e.BytesReceived / 1024f + "kb of " + e.TotalBytesToReceive / 1024f + "kb)");
// Assign to outer variables to allow busy-wait to check.
lReceived = e.BytesReceived;
lTotal = e.TotalBytesToReceive;
};
// Set a delegate to watch for when the download is complete
oWebClient.OpenReadCompleted += delegate(object sender, OpenReadCompletedEventArgs e)
{
// Indicate that things are done
notifier.Set();
};
oWebClient.DownloadFileAsync(new Uri(sUrl + "?" + sPostData), sTempFile);
// wait for signal to proceed
notifier.WaitOne();
}
I have expanded on @OJ's answer to instead set the notifier when the OpenReadCompleted
fires. This will stop the thread from hanging if the file errors during download.
Ref: WebClient DownloadFileAsync hangs
精彩评论