un moyen plus rapide de télécharger plusieurs fichiers

Je dois télécharger environ 2 millions de fichiers du site Web de la SEC. chaque fichier a une URL unique et pèse en moyenne 10 Ko. Voici ma mise en œuvre actuelle:

List urls = new List(); // ... initialize urls ... WebBrowser browser = new WebBrowser(); foreach (ssortingng url in urls) { browser.Navigate(url); while (browser.ReadyState != WebBrowserReadyState.Complete) Application.DoEvents(); StreamReader sr = new StreamReader(browser.DocumentStream); StreamWriter sw = new StreamWriter(), url.Subssortingng(url.LastIndexOf('/'))); sw.Write(sr.ReadToEnd()); sr.Close(); sw.Close(); } 

le temps prévu est d’environ 12 jours … existe-t-il un moyen plus rapide?

Edit: d’ ailleurs, la gestion des fichiers locaux ne prend que 7% du temps

Edit: ceci est ma dernière implémentation:

  void Main(void) { ServicePointManager.DefaultConnectionLimit = 10000; List urls = new List(); // ... initialize urls ... int resortinges = urls.AsParallel().WithDegreeOfParallelism(8).Sum(arg => downloadFile(arg)); } public int downloadFile(ssortingng url) { int resortinges = 0; retry: try { HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(url); webrequest.Timeout = 10000; webrequest.ReadWriteTimeout = 10000; webrequest.Proxy = null; webrequest.KeepAlive = false; webresponse = (HttpWebResponse)webrequest.GetResponse(); using (Stream sr = webrequest.GetResponse().GetResponseStream()) using (FileStream sw = File.Create(url.Subssortingng(url.LastIndexOf('/')))) { sr.CopyTo(sw); } } catch (Exception ee) { if (ee.Message != "The remote server returned an error: (404) Not Found." && ee.Message != "The remote server returned an error: (403) Forbidden.") { if (ee.Message.StartsWith("The operation has timed out") || ee.Message == "Unable to connect to the remote server" || ee.Message.StartsWith("The request was aborted: ") || ee.Message.StartsWith("Unable to read data from the transport connection: ") || ee.Message == "The remote server returned an error: (408) Request Timeout.") resortinges++; else MessageBox.Show(ee.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); goto retry; } } return resortinges; } 

Exécutez les téléchargements simultanément plutôt que séquentiellement, et définissez un MaxDegreeOfParallelism raisonnable, sinon vous essaierez de faire trop de requêtes simultanées qui ressembleront à une attaque par le DOS:

  public static void Main(ssortingng[] args) { var urls = new List(); Parallel.ForEach( urls, new ParallelOptions{MaxDegreeOfParallelism = 10}, DownloadFile); } public static void DownloadFile(ssortingng url) { using(var sr = new StreamReader(HttpWebRequest.Create(url).GetResponse().GetResponseStream())) using(var sw = new StreamWriter(url.Subssortingng(url.LastIndexOf('/')))) { sw.Write(sr.ReadToEnd()); } } 

Télécharger des fichiers dans plusieurs threads. Le nombre de threads dépend de votre débit. Regardez également les classes WebClient et HttpWebRequest . Échantillon simple:

 var list = new[] { "http://google.com", "http://yahoo.com", "http://stackoverflow.com" }; var tasks = Parallel.ForEach(list, s => { using (var client = new WebClient()) { Console.WriteLine("starting to download {0}", s); ssortingng result = client.DownloadSsortingng((ssortingng)s); Console.WriteLine("finished downloading {0}", s); } }); 

J’utiliserais plusieurs threads en parallèle, avec un WebClient . Je recommande de définir le degré maximum de parallélisme sur le nombre de threads souhaités, car un degré de parallélisme non spécifié ne fonctionne pas bien pour les tâches de longue durée. J’ai utilisé 50 téléchargements parallèles dans l’un de mes projets sans problème, mais en fonction de la vitesse d’un téléchargement individuel, une valeur beaucoup plus faible pourrait suffire.

Si vous téléchargez plusieurs fichiers en parallèle à partir du même serveur, vous êtes par défaut limité à un petit nombre (2 ou 4) de téléchargements en parallèle. Bien que la norme http spécifie une limite aussi basse, de nombreux serveurs ne l’imposent pas. Use ServicePointManager.DefaultConnectionLimit = 10000; augmenter la limite.