C# 等待下载完成
我正在尝试创建一个简单的程序来下载一些文件。我在网上找到了一些现成的解决方案,但我无法让它按我想要的方式工作。我用这个:C# 等待下载完成,c#,download,.net-4.5,C#,Download,.net 4.5,我正在尝试创建一个简单的程序来下载一些文件。我在网上找到了一些现成的解决方案,但我无法让它按我想要的方式工作。我用这个: private void startDownload(string toDownload, string saveLocation) { Thread thread = new Thread(() => { WebClient client = new WebClient();
private void startDownload(string toDownload, string saveLocation)
{
Thread thread = new Thread(() =>
{
WebClient client = new WebClient();
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
client.DownloadFileAsync(new Uri(toDownload), saveLocation);
});
thread.Start();
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
this.BeginInvoke((MethodInvoker)delegate
{
double bytesIn = double.Parse(e.BytesReceived.ToString());
double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
double percentage = bytesIn / totalBytes * 100;
labelPercentage.Text = "Downloading " + Convert.ToInt32(percentage) + "% - " + Convert.ToInt32(bytesIn / 1024) + " / " + Convert.ToInt32(totalBytes / 1024) + " kB";
progressBar1.Value = int.Parse(Math.Truncate(percentage).ToString());
});
}
void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
this.BeginInvoke((MethodInvoker)delegate
{
textBoxLog.AppendText("OK");
});
}
下载完成后,我想让程序继续(下载下一个文件/显示“OK”消息/执行下一行代码中的任何操作)。
以目前的形式,如果我把eg
private void button1_Click(object sender, EventArgs e)
{
startDownload(url, localpath + @"\file.zip");
textBoxLog.AppendText("the cake is a lie");
}
它先给我看这段文字,然后再给我看“OK”
我从c#/.net开始,以前从未学习过面向对象编程,所以这对我来说是双重挑战,我自己也无法解决。如果能给我一个相对简单的解释,我将不胜感激。
startDownload
会在一个新线程上启动下载,因此当您调用startDownload
时,它会启动线程,之后的其余代码会立即继续,因为它位于一个单独的线程上。这就是为什么您在“OK”之前看到“蛋糕是谎言”的原因。startDownload
在一个新线程上启动下载,因此当您调用startDownload
时,它会启动线程,之后的其余代码会立即继续,因为它位于一个单独的线程上。这就是为什么您会在“OK”之前看到“蛋糕是谎言”的原因。您可以让startDownload通过如下方式等待异步文件下载:
private bool downloadComplete = false;
private void startDownload(Uri toDownload, string saveLocation)
{
string outputFile = Path.Combine(saveLocation, Path.GetFileName(toDownload.AbsolutePath));
WebClient client = new WebClient();
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
client.DownloadFileAsync(toDownload, outputFile);
while (!downloadComplete)
{
Application.DoEvents();
}
downloadComplete = false;
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
// No changes in this method...
}
void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
this.BeginInvoke((MethodInvoker)delegate
{
textBoxLog.AppendText("OK");
downloadComplete = true;
});
}
下载队列
private void button1_Click(object sender, EventArgs e)
{
FireDownloadQueue(urls, localpath);
textBoxLog.AppendText("the cake is a lie");
}
private async void FireDownloadQueue(Uri[] toDownload, string saveLocation)
{
foreach (var url in urls)
{
await Task.Run(() => startDownload(url, localpath));
}
}
然而,我认为您最好阅读并编写您自己的带有适当检查和事件的downloader类。。。
下面是Hemanshu Bhojak()的一个很好的例子,您可以对其进行扩展:
public class Downloader
{
public async Task Download(string url, string saveAs)
{
var httpClient = new HttpClient();
var response = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, url));
var parallelDownloadSuported = response.Headers.AcceptRanges.Contains("bytes");
var contentLength = response.Content.Headers.ContentLength ?? 0;
if (parallelDownloadSuported)
{
const double numberOfParts = 5.0;
var tasks = new List<Task>();
var partSize = (long)Math.Ceiling(contentLength / numberOfParts);
File.Create(saveAs).Dispose();
for (var i = 0; i < numberOfParts; i++)
{
var start = i*partSize + Math.Min(1, i);
var end = Math.Min((i + 1)*partSize, contentLength);
tasks.Add(
Task.Run(() => DownloadPart(url, saveAs, start, end))
);
}
await Task.WhenAll(tasks);
}
}
private async void DownloadPart(string url, string saveAs, long start, long end)
{
using (var httpClient = new HttpClient())
using (var fileStream = new FileStream(saveAs, FileMode.Open, FileAccess.Write, FileShare.Write))
{
var message = new HttpRequestMessage(HttpMethod.Get, url);
message.Headers.Add("Range", string.Format("bytes={0}-{1}", start, end));
fileStream.Position = start;
await httpClient.SendAsync(message).Result.Content.CopyToAsync(fileStream);
}
}
}
有点类似于:
public class Downloader
{
public event EventHandler DownloadProgress;
DownloaderEventArgs downloaderEventArgs;
public void DownloadStarted(DownloaderEventArgs e)
{
EventHandler downloadProgress = DownloadProgress;
if (downloadProgress != null)
downloadProgress(this, e);
}
// ...
}
class DownloaderEventArgs : EventArgs
{
public string Filename { get; private set; }
public int Progress { get; private set; }
public DownloaderEventArgs(int progress, string filename)
{
Progress = progress;
Filename = filename;
}
public DownloaderEventArgs(int progress) : this(progress, String.Empty)
{
Progress = progress;
}
}
您可以通过以下方式让startDownload等待异步文件下载:
private bool downloadComplete = false;
private void startDownload(Uri toDownload, string saveLocation)
{
string outputFile = Path.Combine(saveLocation, Path.GetFileName(toDownload.AbsolutePath));
WebClient client = new WebClient();
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
client.DownloadFileAsync(toDownload, outputFile);
while (!downloadComplete)
{
Application.DoEvents();
}
downloadComplete = false;
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
// No changes in this method...
}
void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
this.BeginInvoke((MethodInvoker)delegate
{
textBoxLog.AppendText("OK");
downloadComplete = true;
});
}
下载队列
private void button1_Click(object sender, EventArgs e)
{
FireDownloadQueue(urls, localpath);
textBoxLog.AppendText("the cake is a lie");
}
private async void FireDownloadQueue(Uri[] toDownload, string saveLocation)
{
foreach (var url in urls)
{
await Task.Run(() => startDownload(url, localpath));
}
}
然而,我认为您最好阅读并编写您自己的带有适当检查和事件的downloader类。。。
下面是Hemanshu Bhojak()的一个很好的例子,您可以对其进行扩展:
public class Downloader
{
public async Task Download(string url, string saveAs)
{
var httpClient = new HttpClient();
var response = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, url));
var parallelDownloadSuported = response.Headers.AcceptRanges.Contains("bytes");
var contentLength = response.Content.Headers.ContentLength ?? 0;
if (parallelDownloadSuported)
{
const double numberOfParts = 5.0;
var tasks = new List<Task>();
var partSize = (long)Math.Ceiling(contentLength / numberOfParts);
File.Create(saveAs).Dispose();
for (var i = 0; i < numberOfParts; i++)
{
var start = i*partSize + Math.Min(1, i);
var end = Math.Min((i + 1)*partSize, contentLength);
tasks.Add(
Task.Run(() => DownloadPart(url, saveAs, start, end))
);
}
await Task.WhenAll(tasks);
}
}
private async void DownloadPart(string url, string saveAs, long start, long end)
{
using (var httpClient = new HttpClient())
using (var fileStream = new FileStream(saveAs, FileMode.Open, FileAccess.Write, FileShare.Write))
{
var message = new HttpRequestMessage(HttpMethod.Get, url);
message.Headers.Add("Range", string.Format("bytes={0}-{1}", start, end));
fileStream.Position = start;
await httpClient.SendAsync(message).Result.Content.CopyToAsync(fileStream);
}
}
}
有点类似于:
public class Downloader
{
public event EventHandler DownloadProgress;
DownloaderEventArgs downloaderEventArgs;
public void DownloadStarted(DownloaderEventArgs e)
{
EventHandler downloadProgress = DownloadProgress;
if (downloadProgress != null)
downloadProgress(this, e);
}
// ...
}
class DownloaderEventArgs : EventArgs
{
public string Filename { get; private set; }
public int Progress { get; private set; }
public DownloaderEventArgs(int progress, string filename)
{
Progress = progress;
Filename = filename;
}
public DownloaderEventArgs(int progress) : this(progress, String.Empty)
{
Progress = progress;
}
}
我不明白这个问题。下载完成后,您已经完成了一些工作。你到底不能做什么?你试了什么?你被困在哪里了?我将下载大约50个文件,这些文件将在一个循环中完成。foreach(文件中的字符串文件)startDownload(…)将同时下载50个文件,progressbar将患帕金森病,程序将继续做在所有文件下载之前不应该做的事情。使用thread.Join//等待线程完成)伟大的线程:我不理解这个问题。下载完成后,您已经完成了一些工作。你到底不能做什么?你试了什么?你被困在哪里了?我将下载大约50个文件,这些文件将在一个循环中完成。foreach(文件中的字符串文件)startDownload(…)将同时下载50个文件,progressbar将患帕金森病,程序将继续做在所有文件下载之前不应该做的事情。使用thread.Join//等待线程完成)很棒的线程:赞成“Application.DoEvents();”一行。这是我遗漏的拼图的一部分。竖起大拇指看“Application.DoEvents();”一行。这是我丢失的拼图的一部分。