Pobieranie plików w kolejce + Thread

0

Witam uprzejmie.

Mam na liście np. 10 plików (adresy do nich). Chciałbym je oczywiście pobrać na dysk. O ile pobieranie jednego pliku nie stanowi problemu, to już pobranie 10-ciu plików po kolei jest dla mnie nie lada wyzwaniem.

Do pobierania pliku i pokazania postępu używam kodu (google):

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.IO;
using System.Threading;

namespace DownloadManager
{
   public partial class Form1 : Form
   {
      // The thread inside which the download happens
      private Thread thrDownload;
      // The stream of data retrieved from the web server
      private Stream strResponse;
      // The stream of data that we write to the harddrive
      private Stream strLocal;
      // The request to the web server for file information
      private HttpWebRequest webRequest;
      // The response from the web server containing information about the file
      private HttpWebResponse webResponse; 
      // The progress of the download in percentage
      private static int PercentProgress;
      // The delegate which we will call from the thread to update the form
      private delegate void UpdateProgessCallback(Int64 BytesRead, Int64 TotalBytes);

      public Form1()
      {
         InitializeComponent();
      }

      private void btnDownload_Click(object sender, EventArgs e)
      {
         // Let the user know we are connecting to the server
         lblProgress.Text = "Download Starting";
         // Create a new thread that calls the Download() method
         thrDownload = new Thread(Download);
         // Start the thread, and thus call Download()
         thrDownload.Start();
      }

      private void UpdateProgress(Int64 BytesRead, Int64 TotalBytes)
      {
         // Calculate the download progress in percentages
         PercentProgress = Convert.ToInt32((BytesRead * 100) / TotalBytes);
         // Make progress on the progress bar
         prgDownload.Value = PercentProgress;
         // Display the current progress on the form
         lblProgress.Text = "Downloaded " + BytesRead + " out of " + TotalBytes + " (" + PercentProgress + "%)";
      }

      private void Download()
      {
         using (WebClient wcDownload = new WebClient())
         {
            try
            {
               // Create a request to the file we are downloading
               webRequest = (HttpWebRequest)WebRequest.Create(txtUrl.Text);
               // Set default authentication for retrieving the file
               webRequest.Credentials = CredentialCache.DefaultCredentials;
               // Retrieve the response from the server
               webResponse = (HttpWebResponse)webRequest.GetResponse();
               // Ask the server for the file size and store it
               Int64 fileSize = webResponse.ContentLength;

               // Open the URL for download 
               strResponse = wcDownload.OpenRead(txtUrl.Text);
               // Create a new file stream where we will be saving the data (local drive)
               strLocal = new FileStream(txtPath.Text, FileMode.Create, FileAccess.Write, FileShare.None);

               // It will store the current number of bytes we retrieved from the server
               int bytesSize = 0;
               // A buffer for storing and writing the data retrieved from the server
               byte[] downBuffer = new byte[2048];

               // Loop through the buffer until the buffer is empty
               while ((bytesSize = strResponse.Read(downBuffer, 0, downBuffer.Length)) > 0)
               {
                  // Write the data from the buffer to the local hard drive
                  strLocal.Write(downBuffer, 0, bytesSize);
                  // Invoke the method that updates the form's label and progress bar
                  this.Invoke(new UpdateProgessCallback(this.UpdateProgress), new object[] { strLocal.Length, fileSize });
               }
            }
            finally
            {
               // When the above code has ended, close the streams
               strResponse.Close();
               strLocal.Close();
            }
         }
      }

      private void btnStop_Click(object sender, EventArgs e)
      {
         // Close the web response and the streams
         webResponse.Close();
         strResponse.Close();
         strLocal.Close();
         // Abort the thread that's downloading
         thrDownload.Abort();
         // Set the progress bar back to 0 and the label
         prgDownload.Value = 0;
         lblProgress.Text = "Download Stopped";
      }
   }
}

Ale jak pisałem, chciałbym pobrać np. 10 plików po kolei.
Testowałem :

  • uruchomienie w pętli, jednak uruchamia mi to od razu 10 pobierań
  • starałem się czekać na zakończenie wątku - jednak nie bardzo mi to wychodzi
  • kombinowałem ze zmienną bool : podczas pobierania zmienna = false, po zakończeniu pobierania zmienna = true i rozpocznij nowe pobieranie, zmieniając stan zmiennej na false. - też nie bardzo.

Chciałem uruchomić pętlę w osobnym wątku, czyli jest wątek główny, w nim pętla która uruchamia wątek pobierający plik - ale tu znowu problem bo nie umiem utworzyć odpowiedniego delegata - dostaje błąd, że próbuję się dostać do progresbara, który został utworzony w innym wątku.

Tak więc moje pytanie, jak zrealizować pobieranie plików po kolei, z użyciem w/w kodu ?
Czytałem o WaitOne, ThreadPool - ale jak na razie to dla mnie czarna magia ;/ Jeszcze dobrze nie oswoiłem się z wątkami :/

Btw. oczywiście jestem początkujący.

0

Problem tkwi w tym, że uruchamiasz osobne wątki dla każdego pobieranego pliku. Masz jeden wątek, wystarczy, że będzie on wywołał po kolei Download() z odpowiednimi parametrami (typu adres pliku na serwerze, ścieżka do zapisu na dysku, itp).
Zamiast tego:

 thrDownload = new Thread(Download);

daj na przykład:

 thrDownload = new Thread(StartDownload);

i potem:

private void StartDownload()
{
     Download("Jakis adres pliku");
     Download("Jakis adres innego pliku");
     Download("Jakis adres jeszcze innego pliku");
}
0

Dzięki za odpowiedź, ale niestety nie nadal nie działa.

Wywołanie wątku :

        private void button1_Click(object sender, EventArgs e)
        {
                lblProgress.Text = "Download starting";
                thrDownload = new Thread(StartDownload);
                thrDownload.IsBackground = true;
                thrDownload.Start();
        }

Tak jak pisałeś (parametry testowe) :

        private void StartDownload()
        {
            Download(1);
            Download(2);
            Download(3);
        }

Funkcja służąca do pobierania :

      private void Download(object abc)
        {
            int liczba = (int)abc;
            using (WebClient wcDownload = new WebClient())
            {
                try
                {
                    webRequest = (HttpWebRequest)WebRequest.Create(txtUrl.Text);
                    webRequest.Credentials = CredentialCache.DefaultCredentials;

                    webResponse = (HttpWebResponse)webRequest.GetResponse();
                    Int64 fileSize = webResponse.ContentLength;

                    strResponse = wcDownload.OpenRead(txtUrl.Text);
                    strLocal = new FileStream(txtPath.Text+"test"+liczba.ToString()+".jpg", FileMode.Create, FileAccess.Write, FileShare.None);

                    int bytesSize = 0;
                    byte[] downBuffer = new byte[2048];

                    while((bytesSize = strResponse.Read(downBuffer,0,downBuffer.Length))>0)
                    {
                        strLocal.Write(downBuffer,0,bytesSize);
                        this.Invoke(new UpdateProgressCallback(this.UpdateProgress),new object[]{strLocal.Length,fileSize});
                    }
                }
                finally
                {
                    strResponse.Close();
                    strLocal.Close();
                }

            }
            //this.thrDownload.Join();
        }

Pobiera tylko jeden raz, po czym program jakby się zawieszał. Na firewall'u nie widzę żadnego ruchu sieciowego - nic.
Byłbym wdzięczny za pomoc, bo męczę się z tym już od dłuższego czasu i nie mogę ruszyć z miejsca ;/

// Znalazłem kod kawałek kodu :

definicja :
AutoResetEvent resetEvent = new AutoResetEvent(false);

następnie w kodzie w jakiejś pętli jest :

((AutoResetEvent)e.UserState).Set();

o co chodzi ? Bo mam przeczucie, że może mi się to przydać.

0

przekombinowales ten download
a wystarczy

System.Net.WebRequest req = System.Net.WebRequest.Create(@"http://bi.gazeta.pl/im/8/8320/z8320858D.jpg");
            req.UseDefaultCredentials = true;
            req.Proxy.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
            var res = req.GetResponse();
            var fileSize = res.ContentLength;
            Stream resS = res.GetResponseStream();
            // tu czytamy ...
            resS.Close();

wielkosc pliku mozesz przeczytac z WebResponse.ContentLength
na podstawie responseStream mozesz utworzyc inny jesli ci potrzeba, np. StreamReader
lub po prostu uzywac metody Read z klasy Stream do odczytu, tak jak to robisz teraz

nie mam sily teraz analizowac dokladnie twojego kodu, wiec ktory kawalek sprawia problem to ci nie powiem
ale w metodzie Download nie widze deklaracji strumieni, tylko nie mow ze to zmienne "globalne"!

0
mr.hex napisał(a)

(...) Pobiera tylko jeden raz, po czym program jakby się zawieszał. Na firewall'u nie widzę żadnego ruchu sieciowego - nic. (...)

Od sprawdzania czy program się zawiesza i czy występują jakieś błędy jest debugger a nie firewall. :P Ustaw sobie breakpointy albo zastosuj metodę "na MsgBox" i będziesz widział czy program się wykonuje dalej czy nie. Powinieneś dodać też blok Catch żeby przechwytywać możliwe informacje o błędach. Nie widzę nigdzie webResponse.Close (może to jet przyczyna?). Sprawdź też czy Ci wychodzi z pętli prawidłowo i dla celów testowych:

//this.Invoke(new UpdateProgressCallback(this.UpdateProgress),new object[]{strLocal.Length,fileSize});

Bo jeśli źle to zaimplementowałeś może tutaj tkwi problem.

Zgodzę się z poprzednikiem, że przekombinowałeś. Powinieneś wybrać albo HttpWebRequest+HttpWebResponse albo WebClient, a nie oba jednocześnie.

Edit:
Jeszcze jedno - możesz też spróbować tworzyć webRequest i webResponse wewnątrz Download(), a nie wewnątrz klasy.

0

mr.hex - udało się rozwiązać problem?

1 użytkowników online, w tym zalogowanych: 0, gości: 1