2009-09-17 15 views
6

Sto facendo un programma che scarica i file su http.Questo stream non supporta le operazioni di ricerca. HttpWebResponse

L'ho scaricato, tuttavia voglio essere in grado di mettere in pausa i download, chiudere il programma e riprenderli di nuovo in un secondo momento.

Conosco il percorso in cui li sto scaricando.

Sto scaricando il file tramite HttpWebResponse e leggendo la risposta in un flusso utilizzando GetResponseStream.

Quando chiudo l'app e la riavvio, sono bloccato su come riprendere il download. Ho provato a fare una ricerca sul flusso ma afferma che non è supportato.

Quale sarebbe il modo migliore per farlo?

+0

Ricordare che è necessario riavviare il server: non è possibile farlo da soli. Questa è la ragione per la risposta "AddRange" qui sotto. –

risposta

9

Se il server supporta questo è necessario inviare l'intestazione Range HTTP con la tua richiesta utilizzando il metodo AddRange:

request.AddRange(1024); 

Questo indicherà al server per iniziare a inviare il file dopo il 1 ° kilobyte. Quindi leggi il flusso di risposta normalmente.

Per verificare se un server supporta la ripresa è possibile inviare una richiesta HEAD e verificare se invia l'intestazione Accept-Ranges: bytes.

+5

Vuoi aggiungere un collegamento ai documenti MSDN? http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.addrange.aspx –

2

Che ne dici di una classe 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

Questa classe funziona anche se il server non accetta la ripresa? – Smith

+0

Non so cosa sia "riprendere". HTTP 1.1 definisce un'intestazione Range, di cui questa classe fa affidamento. se il server fa HTTP 1.1, allora Range e può essere contattato da questa classe. – Cheeso

+0

per 'riprendere' intendevo' range header', grazie per il chiarimento – Smith

0

La soluzione è soddisfacente, ma funzionerà solo nei casi in cui il server invia un'intestazione Content-Length. Questa intestazione non sarà presente nei contenuti generati dinamicamente.

Inoltre, questa soluzione invia una richiesta per ogni lettura. Se il contenuto cambia sul server tra le richieste, otterrai risultati incoerenti.

Migliorerei su questo, memorizzando i dati localmente - su disco o in memoria. Quindi, puoi cercarlo tutto ciò che desideri. Non ci saranno problemi di incoerenza e per scaricarlo è necessario un solo HttpWebRequest.

Problemi correlati