簡體   English   中英

如何使用webclient和線程下載多個文件?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM