Comment télécharger Async plusieurs fichiers en utilisant webclient, mais un à la fois?

Il a été étonnamment difficile de trouver un exemple de code de téléchargement de plusieurs fichiers en utilisant la méthode asynchrone de la classe webclient, mais en téléchargeant un à la fois.

Comment puis-je lancer un téléchargement asynchrone, mais attendre que le premier soit terminé jusqu'au second, etc. Fondamentalement un qué.

(notez que je ne veux pas utiliser la méthode de synchronisation, en raison de la fonctionnalité accrue de la méthode asynchrone.)

Le code ci-dessous démarre tous mes téléchargements à la fois. (la barre de progression est tout sur la place)

private void downloadFile(string url)
        {
            WebClient client = new WebClient();

            client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
            client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);

            // Starts the download
            btnGetDownload.Text = "Downloading...";
            btnGetDownload.Enabled = false;
            progressBar1.Visible = true;
            lblFileName.Text = url;
            lblFileName.Visible = true;
            string FileName = url.Substring(url.LastIndexOf("/") + 1,
                            (url.Length - url.LastIndexOf("/") - 1));
             client.DownloadFileAsync(new Uri(url), "C:\Test4\" + FileName);

        }

        void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {

        }

        void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {
            double bytesIn = double.Parse(e.BytesReceived.ToString());
            double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
            double percentage = bytesIn / totalBytes * 100;
            progressBar1.Value = int.Parse(Math.Truncate(percentage).ToString());
        }
24
demandé sur stormist 2011-08-09 11:08:07

3 réponses

Ce que j'ai fait est de remplir une file d'attente contenant toutes mes URL, puis je télécharge chaque élément dans la file d'attente. Quand il n'y a plus d'éléments, je peux alors traiter tous les éléments. Je me suis moqué du code ci-dessous. Gardez à l'esprit que le code ci-dessous est destiné au téléchargement de chaînes et non de fichiers. Il ne devrait pas être trop difficile de modifier le code ci-dessous.

    private Queue<string> _items = new Queue<string>();
    private List<string> _results = new List<string>();

    private void PopulateItemsQueue()
    {
        _items.Enqueue("some_url_here");
        _items.Enqueue("perhaps_another_here");
        _items.Enqueue("and_a_third_item_as_well");

        DownloadItem();
    }

    private void DownloadItem()
    {
        if (_items.Any())
        {
            var nextItem = _items.Dequeue();

            var webClient = new WebClient();
            webClient.DownloadStringCompleted += OnGetDownloadedStringCompleted;
            webClient.DownloadStringAsync(new Uri(nextItem));
            return;
        }

        ProcessResults(_results);
    }

    private void OnGetDownloadedStringCompleted(object sender, DownloadStringCompletedEventArgs e)
    {
        if (e.Error == null && !string.IsNullOrEmpty(e.Result))
        {
            // do something with e.Result string.
            _results.Add(e.Result);
        }
        DownloadItem();
    }

Modifier: J'ai modifié votre code pour utiliser une File d'attente. Pas tout à fait sûr de la façon dont vous vouliez que le progrès fonctionne. Je suis sûr que si vous vouliez les progrès à pour tous les téléchargements, vous pouvez stocker le nombre d'éléments dans la méthode' PopulateItemsQueue () ' et utiliser ce champ dans la méthode progress changed.

    private Queue<string> _downloadUrls = new Queue<string>();

    private void downloadFile(IEnumerable<string> urls)
    {
        foreach (var url in urls)
        {
            _downloadUrls.Enqueue(url);
        }

        // Starts the download
        btnGetDownload.Text = "Downloading...";
        btnGetDownload.Enabled = false;
        progressBar1.Visible = true;
        lblFileName.Visible = true;

        DownloadFile();
    }

    private void DownloadFile()
    {
        if (_downloadUrls.Any())
        {
            WebClient client = new WebClient();
            client.DownloadProgressChanged += client_DownloadProgressChanged;
            client.DownloadFileCompleted += client_DownloadFileCompleted;

            var url = _downloadUrls.Dequeue();
            string FileName = url.Substring(url.LastIndexOf("/") + 1,
                        (url.Length - url.LastIndexOf("/") - 1));

            client.DownloadFileAsync(new Uri(url), "C:\\Test4\\" + FileName);
            lblFileName.Text = url;
            return;
        }

        // End of the download
        btnGetDownload.Text = "Download Complete";
    }

    private void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
    {
        if (e.Error != null)
        {
            // handle error scenario
            throw e.Error;
        }
        if (e.Cancelled)
        {
            // handle cancelled scenario
        }
        DownloadFile();
    }

    void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
    {
        double bytesIn = double.Parse(e.BytesReceived.ToString());
        double totalBytes = double.Parse(e.TotalBytesToReceive.ToString());
        double percentage = bytesIn / totalBytes * 100;
        progressBar1.Value = int.Parse(Math.Truncate(percentage).ToString());
    }
34
répondu Luke Baulch 2012-02-16 00:16:38

J'ai du mal à comprendre où est le problème. Si vous appelez seulement la méthode asynchrone pour le premier fichier, ne téléchargera-t-il pas seulement ce fichier? Pourquoi ne pas utiliser l'événement client_downlaodFileCompleted pour lancer le prochain téléchargement de fichier en fonction d'une valeur passée par AsyncCompletedEvents, ou maintenir une liste de fichiers téléchargés en tant que variable statique et avoir client_DownloadFileCompleted itérer la liste pour trouver le prochain fichier à télécharger.

J'espère que cela aide, mais veuillez poster plus d'informations si je ont miunderstood votre question.

2
répondu Jason James 2011-08-09 07:15:41

Je ferais une nouvelle méthode, par exemple nommée getUrlFromQueue qui me renvoie une nouvelle url de la file d'attente (collection ou tableau) et la supprime.. ensuite, il appelle downloadFile (url) - et dans client_DownloadFileCompleted j'appelle à nouveau getUrlFromQueue.

1
répondu MilMike 2011-08-09 07:15:30