簡體   English   中英

使用c#並行下載多個文件

[英]Download multiple files in parallel using c#

我想使用 C# 並行下載文件。 為此,我編寫了這段運行良好的代碼,但問題是 UI 凍結了。

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace FileDownloader
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private static int count = 1;
        private static string f= "lecture";
        private string URL = "www.someexample.com";

        public MainWindow()
        {
            InitializeComponent();
        }

        public static string GetDirectoryListingRegexForUrl(string url)
        {
            if (url.Equals(URL))
            {
                return "<a href=\".*\">(?<name>.*)</a>";
            }
            throw new NotSupportedException();
        }

        public  void DownloadP(string[] urls)
        {
            Parallel.ForEach(urls.ToList(), new ParallelOptions { MaxDegreeOfParallelism = 10 }, DownloadFile);
        }

        private void DownloadFile(string url)
        {
           using(WebClient client=new WebClient())
           {
               if (url.EndsWith(".pdf"))
               {
                   int nextIndex = Interlocked.Increment(ref count);

                   client.DownloadFile(url, f + nextIndex + ".pdf");
                   this.Dispatcher.Invoke(() => {
                       listbox.Items.Add(url);
                   });
               }
           }
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            DownloadP(listofFiles);
        }
    }
}

您可以將async/await與新的WebClient方法DownloadFileTaskAsync結合使用。

private async Task DownloadFile(string url)
{
    if (!url.EndsWith(".pdf"))
    {
        return;
    }

    using (var client = new WebClient())
    {
        int nextIndex = Interlocked.Increment(ref count);

        await client.DownloadFileTaskAsync(url, "lecture" + nextIndex + ".pdf");
        listBox.Items.Add(url);

    }
}

private async void Button_OnClick(object sender, RoutedEventArgs e)
{
    button.IsEnabled = false;
    await DownloadFiles(urlList);
    button.IsEnabled = true;
}

private async Task DownloadFiles(IEnumerable<string> urlList)
{
    foreach (var url in urlList)
    {
        await DownloadFile(url);
    }
}

而不是使用client.DownloadFile使用client.DownloadFileAsync這樣

var webClient=new WebClient();
webClient.DownloadFileCompleted += webClient_DownloadFileCompleted;
webClient.DownloadFileAsync("Your url","file_name");

事件

    private void webClient_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
    {
        MessageBox.Show("Download Completed.");
    }

我知道這個問題很舊,但是 WebClient 已經過時且專用。 首先,WPF 使用您應該嘗試遵循的 MVVM 模式,但除了您可以在using System.Net.Http; .

要並行下載多個文件,您可以創建一個並行的 foreach 來處理 HttpClient 必須執行的所有下載。 你做對了,但是 foreach 會阻塞線程,所以在一個新的Task.Run(()=>{// Your Code});

如果您不想自己編寫類似的東西,您可以使用 NuGet 上的碎片下載庫 這個 NuGet 包也在 GitHub 上,如果你想看看它是如何工作的。 如果我想下載很多文件,它經常幫助我,因為它不會阻塞 UI 線程並且易於使用。 要使用它你必須寫這樣的東西:

void Download()
{
    string[] links = new string[]{ 
        "https://google.com",
        "https://speed.hetzner.de/100MB.bin",
        "https://file-examples.com/storage/fe88dacf086398d1c98749c/2017/04/file_example_MP4_1920_18MG.mp4" };
    foreach (var link in links)
    {
        _ = new LoadRequest(link);
    }
    Console.ReadLine();
}

但是您也可以設置 MaxDegreeOfParalism 並且可以在下載時更改它。 您可以設置輸出文件的路徑並為其命名。 HttpClient 的下載完成和進度報告的問題也由此解決。 不好的是這個庫的文檔不是很好。 這里以幾個選項為例。

async Task DownloadAsync()
{
    string[] links = new string[]{
        "https://google.com",
        "https://speed.hetzner.de/100MB.bin",
        "https://file-examples.com/storage/fe88dacf086398d1c98749c/2017/04/file_example_MP4_1920_18MG.mp4" };
    RequestHandler requestHandler = new()
    {
        MaxDegreeOfParallelism = 10
    };

    LoadRequestOptions option = new()
    {
        Progress = new Progress<float>(value => Console.WriteLine(value.ToString("0.0%"))),
        DestinationPath = "C:\\Users\\[UserName]\\Desktop\\",
        RequestCompleated = path => Console.WriteLine("Finished: " + path?.ToString()),
        RequestHandler = requestHandler
    };
    LoadRequest last = null;
    foreach (string link in links)
    {
        last = new LoadRequest(link, option);
    }
    await last.Task;
} 

我希望這可以幫助那些有同樣問題並且不想使用專用 WebClient 的人。

用以下方法重新啟動DownloadP功能:

public async Task DownloadP(string[] urls)
{
  await Task.Factory.StartNew(() => Parallel.ForEach(urls.ToList(), new ParallelOptions { MaxDegreeOfParallelism = 10 }, DownloadFile));
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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