2016-06-30 19 views
0

Ich mache ein Tool zum Herunterladen von Bildern aus dem Internet gleichzeitig mit einem List<Uri> und der WebClient Klasse. Hier ist der relevante Code:WebClient nicht alle Dateien herunterladen, wenn eine Liste von Uris gegeben

Das neue WebClient, die ich benutze:

public class PatientWebClient : WebClient 
{ 
    protected override WebRequest GetWebRequest(Uri uri) 
    { 
     WebRequest w = base.GetWebRequest(uri); 
     w.Timeout = Timeout.Infinite; 
     return w; 
    } 
} 

und die Download-Methoden:

public static void DownloadFiles() 
    { 
     string filename = string.Empty; 

     while (_count < _images.Count()) 
     { 
      PatientWebClient client = new PatientWebClient(); 

      client.DownloadDataCompleted += DownloadCompleted; 
      filename = _images[_count].Segments.Last().ToString(); 
      if (!File.Exists(_destinationFolder + @"\" + filename)) 
      { 
       try 
       { 
        client.DownloadDataAsync(_images[_count], _images[_count]); 
       } 
       catch (Exception ex) 
       { 
        Console.WriteLine(ex.ToString()); 
       } 
      } 
      ++_count; 
     } 
    } 

    private static void DownloadCompleted(object sender, DownloadDataCompletedEventArgs e) 
    { 
     if (e.Error == null) 
     { 
      Uri uri = (Uri)e.UserState; 
      string saveFilename = uri.Segments.Last().ToString(); 

      byte[] fileData = e.Result; 

      if (saveFilename.EndsWith(".jpg") || saveFilename.EndsWith(".png") || saveFilename.EndsWith(".gif")) 
       using (FileStream fileStream = new FileStream(_destinationFolder + @"\" + saveFilename, FileMode.Create)) 
        fileStream.Write(fileData, 0, fileData.Length); 
      else 
       using (FileStream fileStream = new FileStream(_destinationFolder + @"\" + saveFilename + ".jpg", FileMode.Create)) 
        fileStream.Write(fileData, 0, fileData.Length); 
      ++_downloadedCounter; 
      ((WebClient)sender).Dispose(); 
     } 
    } 

Das Problem ist, dass nicht alle Bilder aus der Liste _images werden heruntergeladen. Wenn ich auf den Download-Knopf klicke, wird ein zweites Mal mehr heruntergeladen und es dauert ein paar Klicks, um alles runter zu bringen. Sind die WebClient s abgelaufen, und wenn ja, gibt es eine Möglichkeit, sie den Download automatisch erneut zu versuchen? Wenn nicht, was ist der richtige Weg zur Lösung dieses Problems?

+0

Versuchen Sie den Webclient mit Timeout zu erweitern. Der Webclient verfügt nicht über eine Zeitüberschreitungsfunktion. http://stackoverflow.com/questions/1789627/how-to-change-the-timeout-on-a-net-webclient-object. Du ignorierst auch wenn e.Error! = Null, was passiert da? –

+0

@Stanley können Sie Ihre Frage klären? –

+0

Fügen Sie einige Logging- oder 'Console.WriteLine'-Anweisungen hinzu, damit Sie wissen, was tatsächlich passiert. Schreiben Sie Ihre Zähler, Ihre Dateinamen, Ihre URLs und (wie @Stanley es vorschlägt) und Fehler aus den Ereignisargumenten aus. Versuchen Sie auch, 'fileString.Flush()' am Ende jedes 'DownloadCompleted'-Aufrufs hinzuzufügen. – mdisibio

Antwort

1

Wenn Sie noch dieses Muster verwenden wollen, dieses kein Timeout hat, müssen Sie implementieren, dass mit Hilfe der Timer:

internal class Program 
    { 
    private static int _downloadCounter; 
    private static readonly object _syncObj = new object(); 

    private static void Main(string[] args) 
    { 
     Uri[] uris = {new Uri("http://www.google.com"), new Uri("http://www.yahoo.com")}; 
     foreach (var uri in uris) 
     { 
     var webClient = new WebClient(); 
     webClient.DownloadDataCompleted += OnWebClientDownloadDataCompleted; 
     webClient.DownloadDataAsync(uri); 
     } 
     Thread.Sleep(Timeout.Infinite); 
    } 

    private static void OnWebClientDownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e) 
    { 
     if (e.Error == null) 
     { 
     // OK 
     Console.WriteLine(Encoding.UTF8.GetString(e.Result)); 
     } 
     else 
     { 
     // Error 
     Console.WriteLine(e.Error.ToString()); 
     } 

     lock (_syncObj) 
     { 
     _downloadCounter++; 
     Console.WriteLine("Counter = {0}", _downloadCounter); 
     } 

     var webClient = sender as WebClient; 
     if (webClient == null) return; 
     webClient.DownloadDataCompleted -= OnWebClientDownloadDataCompleted; 
     webClient.Dispose(); 
    } 
    } 
+0

Für den '_downloadedCounter' werde ich' Interlocked.Increment (ref _downloadedCounter); 'verwenden, aber ab jetzt markiere ich dies als die Antwort und wird mehr Tests machen. Danke für deine Hilfe und deinen Rat. –

+0

Manchmal hilft das: ServicePointManager.DefaultConnectionLimit = int.Max; um die maximale Verbindung pro Server zu erhöhen, wenn Sie viele Dateien von einem Server herunterladen –

1

ich so etwas wie dies bedeuten, setzen Timeout von Webclient und den Fehler fangen:

internal class Program 
    { 
    private static void Main(string[] args) 
    { 
     Uri[] uris = {new Uri("http://www.google.com"), new Uri("http://www.yahoo.com")}; 
     Parallel.ForEach(uris, uri => 
     { 
     using (var webClient = new MyWebClient()) 
     { 
      try 
      { 
      var data = webClient.DownloadData(uri); 
      // Success, do something with your data 
      } 
      catch (Exception ex) 
      { 
      // Something is wrong... 
      Console.WriteLine(ex.ToString()); 
      } 
     } 
     }); 
    } 
    } 

    public class MyWebClient : WebClient 
    { 
    protected override WebRequest GetWebRequest(Uri uri) 
    { 
     var w = base.GetWebRequest(uri); 
     w.Timeout = 5000; // 5 seconds timeout 
     return w; 
    } 
    } 
+1

Das Problem mit dem ursprünglichen Beitrag war nicht die Zeitüberschreitung. Das Problem bestand darin, einen asynchronen Download-Task zu starten, ohne darauf zu warten, dass er beendet wurde. Stanleys Ansatz Parallel.ForEach ist eine Möglichkeit, dieses Problem elegant und effizient zu lösen. –

+0

@ EugeneShvets-MSFT Ich teste jetzt das Verhalten seines vorgeschlagenen Codes. Werde Dich auf dem Laufenden halten. –

+0

@ EugeneShvets-MSFT Dieser Ansatz bewirkt, dass nur etwa 30 Dateien heruntergeladen werden, während ich mit meiner Methode ungefähr 300 erhielt. Ich bekomme auch keine Fehler, deshalb bin ich mir nicht sicher, was passiert. –