![](/img/trans.png)
[英]How do I Async download multiple files using webclient, but one at a time?
[英]How to download multiple files using webclient and threading?
我需要使用WebClient
和線程創建多個文件下載器,出於學習目的,我創建了此代碼(如下),文件已正確下載,但有時下載停止並且不再開始運行。 我也想控制ProgressBar
。 此代碼的調用者是一個按鈕。
for (int i = 0; i < 3; i++)
{
Start(
delegate
{
WebClient wc = new WebClient();
if(wc.IsBusy != true)
{
wc.DownloadFileAsync(new Uri("http://ipv4.download.thinkbroadband.com/10MB.zip"), @"D:\File" + Convert.ToString(i) + ".txt");
wc.DownloadProgressChanged +=
delegate(object sender1, DownloadProgressChangedEventArgs e1) {
foreach (ToolStripProgressBar it in statusStrip1.Items)
{
if ((it.Name == "pg" + Convert.ToString(x)) == true)
{
it.Control.Invoke((MethodInvoker)delegate() { it.Value = e1.ProgressPercentage; });
}
}
};
}
});
}
public static Thread Start(Action action)
{
Thread thread = new Thread(() => { action(); });
thread.Start();
return thread;
}
您的程序由於以下幾個原因而無法運行:(我相信)您正在使用多個進度條(每個線程一個),但是WebClient不提供任何信息導致哪個文件觸發了DownloadProgressChanged事件,因此您需要一個每個文件的WebClient實例。
其次,當您將循環變量i傳遞給wc.DownloadFileAsync(new Uri("http://ipv4.download.thinkbroadband.com/10MB.zip"), @"D:\\File" + Convert.ToString(i) + ".txt");
方法中,您將捕獲的引用傳遞給循環變量,而不是值(因為您使用的是引用其范圍之外的變量的委托,google用於“關閉”),這意味着文件開始下載時,它可能會被復制到錯誤的文件。 您可以通過將值傳遞給委托來避免這種情況。
一個示例,它與您的程序並不完全相同,但是您可以輕松地對其進行修改:
var progressBars = new ProgressBar[]
{
this.progressBar1,
this.progressBar2,
this.progressBar3
};
for (int i = 0; i < 3; i++)
{
var webClient = new WebClient();
webClient.DownloadFileAsync(new Uri("http://ipv4.download.thinkbroadband.com/10MB.zip"), @"E:\File" + Convert.ToString(i) + ".txt");
var progressBar = progressBars[i];
webClient.DownloadProgressChanged += (sender1, e1) =>
{
progressBar.Invoke((MethodInvoker)(() =>
{
progressBar.Value = e1.ProgressPercentage;
}));
};
}
您沒有保留對WebClient
的引用,因此從技術上講,垃圾收集器可以在您完成請求后的幾乎任何時間回收它。 您需要在某處保留對它的引用,以使GC無法執行此操作。
幸運的是,這是一個可以解決的問題。 我們可以創建一個新的類,該類將為我們創建一個客戶端,同時還將其內部存儲直到被處理:
public class ClientCreator
{
private static HashSet<WebClient> clients = new HashSet<WebClient>();
public static WebClient CreateClient()
{
WebClient client = new WebClient();
lock (clients)
clients.Add(client);
client.Disposed += (s, args) =>
{
lock (clients) clients.Remove(client);
};
return client;
}
}
現在,您需要做的就是確保在處理完Web客戶端后將其丟棄(無論如何,您確實應該這樣做)。
只需添加wc.DownloadFileCompleted += (s, args) => wc.Dispose();
當您附加其他處理程序時,以便在文件下載完成后將其處理。
還值得注意的是,這里根本不需要創建其他線程。 您的方法已經天生就異步了。 運行幾乎不需要(CPU)時間。 您只需刪除所有代碼即可將其推送到另一個線程,而不會丟失任何內容,而不會阻塞您的UI。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.