2009-09-17 28 views
6

Estoy haciendo un programa que descarga archivos a través de http.Esta secuencia no es compatible con las operaciones de búsqueda. HttpWebResponse

Lo tengo descargando, sin embargo, quiero poder pausar las descargas, cerrar el programa y reanudarlas nuevamente más adelante.

Sé que la ubicación en la que los estoy descargando es compatible con esto.

Estoy descargando el archivo a través de HttpWebResponse y leyendo la respuesta en un Stream usando GetResponseStream.

Cuando cierro la aplicación y la reinicio, no sé cómo reanudar la descarga. Intenté hacer una búsqueda en la transmisión pero dice que no es compatible.

¿Cuál sería la mejor manera de hacerlo?

+0

Tenga en cuenta que tiene que decirle al servidor que se reinicie; no puede hacerlo usted mismo. Esa es la razón de la respuesta 'AddRange' a continuación. –

Respuesta

9

Si el servidor soporta esto usted tiene que enviar la cabecera HTTP con Range su solicitud utilizando el método AddRange:

request.AddRange(1024); 

Esto le dará instrucciones al servidor para empezar a enviar el archivo después de la primera kilobytes. Luego solo lea la secuencia de respuesta como siempre.

Para comprobar si un servidor admite la reanudación, puede enviar una solicitud HEAD y probar si envía el encabezado Accept-Ranges: bytes.

+5

¿Desea agregar un enlace a los documentos de MSDN? http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.addrange.aspx –

2

¿Qué tal una clase HTTPRangeStream?

using System; 
using System.Collections.Generic; 
using System.IO; 
using System.Net; 
using System.Text; 

namespace Ionic.Kewl 
{ 
    public class HTTPRangeStream : Stream 
    { 
     private string url; 
     private long length; 
     private long position; 
     private long totalBytesRead; 
     private int totalReads; 

     public HTTPRangeStream(string URL) 
     { 
      url = URL; 
      HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url); 
      HttpWebResponse result = (HttpWebResponse)request.GetResponse(); 
      length = result.ContentLength; 
     } 

     public long TotalBytesRead { get { return totalBytesRead; } } 
     public long TotalReads  { get { return totalReads; } } 
     public override bool CanRead { get { return true; } } 
     public override bool CanSeek { get { return true; } } 
     public override bool CanWrite { get { return false; } } 
     public override long Length { get { return length; } } 

     public override bool CanTimeout 
     { 
      get 
      { 
       return base.CanTimeout; 
      } 
     } 


     public override long Position 
     { 
      get 
      { 
       return position; 
      } 
      set 
      { 
       if (value < 0) throw new ArgumentException(); 
       position = value; 
      } 
     } 

     public override long Seek(long offset, SeekOrigin origin) 
     { 
      switch (origin) 
      { 
       case SeekOrigin.Begin: 
        position = offset; 
        break; 
       case SeekOrigin.Current: 
        position += offset; 
        break; 
       case SeekOrigin.End: 
        position = Length + offset; 
        break; 
       default: 
        break; 
      } 
      return Position; 
     } 

     public override int Read(byte[] buffer, int offset, int count) 
     { 
      HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url); 
      request.AddRange(Convert.ToInt32(position), Convert.ToInt32(position) + count); 
      HttpWebResponse result = (HttpWebResponse)request.GetResponse(); 
      using (Stream stream = result.GetResponseStream()) 
      { 
       stream.Read(buffer, offset, count); 
       stream.Close(); 
      } 
      totalBytesRead += count; 
      totalReads++; 
      Position += count; 
      return count; 
     } 


     public override void Write(byte[] buffer, int offset, int count) 
     { 
      throw new NotSupportedException(); 
     } 

     public override void SetLength(long value) 
     { 
      throw new NotSupportedException(); 
     } 
     public override void Flush() 
     { 
      throw new NotSupportedException(); 
     } 

    } 
} 
+0

¿Funciona esta clase incluso si el servidor no acepta la reanudación? – Smith

+0

No sé qué es "reanudar". HTTP 1.1 define un encabezado Range, en el que se basa esta clase. si el servidor hace HTTP 1.1, entonces lo hace Rango, y puede ser contactado por esta clase. – Cheeso

+0

por 'reanudación' quiero decir' rango encabezado', gracias por la aclaración – Smith

0

Su solución está muy bien, pero sólo funcionará para los casos en que el servidor envía una cabecera Content-Length. Este encabezado no estará presente en el contenido generado dinámicamente.

Además, esta solución se envía una solicitud para cada lectura. Si el contenido cambia en el servidor entre las solicitudes, obtendrá resultados inconsistentes.

Mejoraría esto almacenando los datos localmente, ya sea en el disco o en la memoria. Entonces, puedes buscar todo lo que quieras. No habrá ningún problema de inconsistencia, y solo necesita una HttpWebRequest para descargarlo.

Cuestiones relacionadas