2010-02-15 51 views
6

Necesito descargar programáticamente un archivo grande antes de procesarlo. ¿Cuál es la mejor manera de hacer eso? Como el archivo es grande, quiero un tiempo específico para esperar para poder salir con fuerza.Cómo descargar mediante programación un archivo grande en C#

Sé de WebClient.DownloadFile(). Pero no parece una manera de esperar un tiempo específico para salir con fuerza.

try 
{ 
    WebClient client = new WebClient(); 
    Uri uri = new Uri(inputFileUrl); 
    client.DownloadFile(uri, outputFile); 
} 
catch (Exception ex) 
{ 
    throw; 
} 

Otra forma es utilizar una utilidad de línea de comandos (wget) para descargar el archivo y disparar usando el comando ProcessStartInfo y el uso de procesos WaitForExit (int ms) a la fuerza de salida.

ProcessStartInfo startInfo = new ProcessStartInfo(); 
//set startInfo object 

try 
{ 
    using (Process exeProcess = Process.Start(startInfo)) 
    { 
     //wait for time specified 
     exeProcess.WaitForExit(1000 * 60 * 60);//wait till 1m 

     //check if process has exited 
     if (!exeProcess.HasExited) 
     { 
      //kill process and throw ex 
      exeProcess.Kill(); 
      throw new ApplicationException("Downloading timed out"); 
     } 
    } 
} 
catch (Exception ex) 
{ 
    throw; 
} 

¿Hay una manera mejor? Por favor ayuda. Gracias.

+0

Cuál es la URI ? es ftp? – t0mm13b

Respuesta

16

Usa un WebRequest y obtén el response stream. Luego lea de la respuesta Stream bloques de bytes y escriba cada bloque en el archivo de destino. De esta manera se puede controlar cuándo parar si la descarga tarda demasiado tiempo, a medida que el control entre trozos y se puede decidir si la descarga se ha agotado el tiempo sobre la base de un reloj:            

 DateTime startTime = DateTime.UtcNow; 
     WebRequest request = WebRequest.Create("http://www.example.com/largefile"); 
     WebResponse response = request.GetResponse(); 
     using (Stream responseStream = response.GetResponseStream()) { 
      using (Stream fileStream = File.OpenWrite(@"c:\temp\largefile")) { 
       byte[] buffer = new byte[4096]; 
       int bytesRead = responseStream.Read(buffer, 0, 4096); 
       while (bytesRead > 0) {  
        fileStream.Write(buffer, 0, bytesRead); 
        DateTime nowTime = DateTime.UtcNow; 
        if ((nowTime - startTime).TotalMinutes > 5) { 
         throw new ApplicationException(
          "Download timed out"); 
        } 
        bytesRead = responseStream.Read(buffer, 0, 4096); 
       } 
      } 
     } 
+0

@orip, ¿cómo es complicado? – juan

+0

@Juan, para uno es sincrónico. La versión asincrónica de este ejemplo se vería muy diferente. Pero también descarta la fachada de WebClient, muy fácil de usar, que oculta la gestión del flujo, que en gran medida es irrelevante el 90% del tiempo. – Josh

+1

orip, su código es mucho más simple. Una ventaja de usar el código de Remus es que puedo saber cuánta porción del archivo se descarga. – hIpPy

7

Cómo sobre el uso de DownloadFileAsync en la clase WebClient. Lo bueno de seguir esta ruta es que puede cancelar la operación llamando al CancelAsync si tarda demasiado. Básicamente, llame a este método, y si transcurre un período de tiempo específico, llame a Cancelar.

4

se le preguntó aquí: C#: Downloading a URL with timeout

solución más simple:

public string GetRequest(Uri uri, int timeoutMilliseconds) 
{ 
    var request = System.Net.WebRequest.Create(uri); 
    request.Timeout = timeoutMilliseconds; 
    using (var response = request.GetResponse()) 
    using (var stream = response.GetResponseStream()) 
    using (var reader = new System.IO.StreamReader(stream)) 
    { 
     return reader.ReadToEnd(); 
    } 
} 

solución mejor (más flexible) es this answer a la misma pregunta, en forma de una clase WebClientWithTimeout ayudante.

+4

webrequest.timeout solo mide el tiempo hasta que se reciben los encabezados de respuesta HTTP, no el tiempo total hasta que se descarga el cuerpo de la respuesta. Es decir. Afecta el tiempo hasta que GetResponse regrese. –

+0

Buen punto, no estaba al tanto de eso – orip

2

Puede utilizar DownloadFileAsync como dijo @BFree y luego tratar con los eventos de la siguiente WebClient

protected virtual void OnDownloadProgressChanged(DownloadProgressChangedEventArgs e); 
protected virtual void OnDownloadFileCompleted(AsyncCompletedEventArgs e); 

A continuación, se puede conocer el porcentaje de avance

e.ProgressPercentage 

Esperanza esto ayuda

Cuestiones relacionadas