2016-06-30 3 views
0

List<Uri>WebClientクラスを同時に使用してインターネットから画像をダウンロードするツールを作成しています。WebクライアントでUrisのリストが指定されている場合、すべてのファイルがダウンロードされない

私が使用しています新しいWebクライアント:

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からのすべての画像ダウンロード中です。ダウンロードボタンを2回クリックすると、さらにダウンロードされ、実際には数回クリックするだけですべてがダウンします。 WebClientはタイムアウトしていますか?そうであれば自動的にダウンロードを再試行する方法がありますか?そうでない場合、この問題を解決する適切な方法は何ですか?

+0

WebClientをタイムアウトで延長してください。 Webclientはタイムアウトの能力を持っていません。 http://stackoverflow.com/questions/1789627/how-to-change-the-timeout-on-a-net-webclient-object e.Error!= nullの場合は無視します。何が起こるのですか? –

+0

@Stanleyあなたの質問を明確にすることができますか? –

+0

いくつかのロギングまたは 'Console.WriteLine'文を追加して、実際に何が起こっているかを知ることができます。カウンター、ファイル名、あなたのURL、(@Stanleyが示唆しているように)イベントargsからエラーを書き出します。また、 'DownloadCompleted'呼び出しの終わりに' fileString.Flush() 'を追加してみてください。 – mdisibio

答えて

1

あなたはまだそのパターンを使用したい場合は、この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

'_downloadCounter'では' Interlocked.Increment(ref _downloadedCounter); 'を使用しますが、今のところ私はこれを答えはより多くのテストをしています。あなたの助けとアドバイスをありがとう。 –

+0

時には、これが役に立ちます:ServicePointManager.DefaultConnectionLimit = int.Max; 1台のサーバーから多数のファイルをダウンロードする場合、サーバーごとの最大接続数を増やす –

1

私は、このような何かを意味するWebクライアントのタイムアウトを設定し、エラーをキャッチ:あなたはタイマーを使用していることを実装する必要があります

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

元の投稿の問題はタイムアウトではありませんでした。この問題は、非同期ダウンロードタスクが完了するのを待つことなく開始されていました。 StanleyのParallel.ForEachアプローチは、その問題をエレガントかつ効率的に解決する方法の1つです。 –

+0

@ EugeneShvets-MSFT私は今、彼の提案されたコードの動作をテストしています。更新されます。 –

+0

@ EugeneShvets-MSFTこの方法では、約30のファイルしかダウンロードされませんが、私の方法では約300がダウンロードされました。私も何かエラーがないので、何が起こっているのか分かりません。 –

関連する問題