2016-06-30 3 views
0

Я делаю инструмент для загрузки изображений из Интернета одновременно с использованием List<Uri> и класса WebClient. Вот соответствующий код:WebClient не загружает все файлы при предоставлении списка Uris

Новый WebClient, что я использую:

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

и методах загрузки:

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(); 
     } 
    } 

Вопрос заключается в том, что не все изображения из списка _images загружаются. Если я нажму кнопку загрузки, второй раз будет загружен, и на самом деле потребуется несколько щелчков мыши, чтобы сбить все. Вывод времени WebClient, и если да, то есть способ заставить их автоматически повторить загрузку? Если нет, то каков правильный способ решения этой проблемы?

+0

Попробуйте расширить веб-клиент с таймаутом. Webclient не имеет возможности для тайм-аута. http://stackoverflow.com/questions/1789627/how-to-change-the-timeout-on-a-net-webclient-object. Вы также игнорируете, если e.Error! = Null, что там происходит? –

+0

@ Стэнли, не могли бы вы уточнить свой вопрос? –

+0

Добавьте некоторые записи или 'Console.WriteLine', чтобы вы знали, что на самом деле происходит. Выпишите свои счетчики, имена ваших файлов, ваш url и (как предлагает @Stanley) и Error from event args. Кроме того, попробуйте добавить 'fileString.Flush()' в конец каждого вызова 'DownloadCompleted'. – mdisibio

ответ

1

Если вы хотите использовать этот шаблон, этот один не имеет тайм-аут, вы должны осуществить это с помощью таймера:

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

Для '_downloadedCounter' я думаю, что буду использовать' Interlocked.Increment (ref_downloadedCounter); ', но на данный момент я отмечаю это как ответ и будет проводить больше тестирования. Спасибо за вашу помощь и совет. –

+0

Иногда это поможет: ServicePointManager.DefaultConnectionLimit = int.Max; для увеличения максимального соединения на сервер, если вы загружаете много файлов с 1 сервера –

1

Я имею в виду что-то вроде этого, установить тайм-аут WebClient и поймать ошибку:

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

Проблема с исходным сообщением не была таймаутом. Проблема заключалась в том, чтобы запустить асинхронную задачу загрузки, не дожидаясь ее завершения. Стенли Parallel.ForEach - это один из способов решения этой проблемы элегантно и эффективно. –

+0

@ EugeneShvets-MSFT Я сейчас тестирую поведение его предлагаемого кода. Будет обновляться. –

+0

@ EugeneShvets-MSFT Этот подход позволяет загружать только около 30 файлов, в то время как я получал около 300 с помощью моего метода. У меня также нет ошибок, поэтому я не уверен, что происходит. –

Смежные вопросы