2012-12-07 29 views
16

Sto tentando di scaricare un file di grandi dimensioni da un URL pubblico. All'inizio sembrava funzionare bene, ma i computer 1/10 sembrano scadere. Il mio tentativo iniziale era di usare WebClient.DownloadFileAsync ma, poiché non sarebbe mai stato completato, ricado all'utilizzo di WebRequest.Create e leggere direttamente i flussi di risposta.WebRequest non riesce a scaricare correttamente i file di grandi dimensioni (~ 1 GB)

La mia prima versione di utilizzo di WebRequest.Create ha riscontrato lo stesso problema di WebClient.DownloadFileAsync. L'operazione scade e il file non viene completato.

La mia prossima versione ha aggiunto tentativi se il download è scaduto. Qui è che è strano. Il download termina con 1 tentativo di finire gli ultimi 7092 byte. Quindi il file viene scaricato con esattamente la stessa dimensione, MA il file è corrotto e si differenzia dal file sorgente. Ora mi aspetterei che la corruzione sia negli ultimi 7092 byte ma non è questo il caso.

Utilizzo di BeyondCompare Ho trovato che ci sono 2 blocchi di byte mancanti dal file corrotto per un totale di 7092 byte mancanti! Questi byte mancanti sono 1CA49FF0 e 1E31F380, molto prima che il download scada e venga riavviato.

Cosa potrebbe succedere qui? Qualche suggerimento su come rintracciare ulteriormente questo problema?

Questo è il codice in questione.

public void DownloadFile(string sourceUri, string destinationPath) 
{ 
    //roughly based on: http://stackoverflow.com/questions/2269607/how-to-programmatically-download-a-large-file-in-c-sharp 
    //not using WebClient.DownloadFileAsync as it seems to stall out on large files rarely for unknown reasons. 

    using (var fileStream = File.Open(destinationPath, FileMode.Create, FileAccess.Write, FileShare.Read)) 
    { 
     long totalBytesToReceive = 0; 
     long totalBytesReceived = 0; 
     int attemptCount = 0; 
     bool isFinished = false; 

     while (!isFinished) 
     { 
      attemptCount += 1; 

      if (attemptCount > 10) 
      { 
       throw new InvalidOperationException("Too many attempts to download. Aborting."); 
      } 

      try 
      { 
       var request = (HttpWebRequest)WebRequest.Create(sourceUri); 

       request.Proxy = null;//http://stackoverflow.com/questions/754333/why-is-this-webrequest-code-slow/935728#935728 
       _log.AddInformation("Request #{0}.", attemptCount); 

       //continue downloading from last attempt. 
       if (totalBytesReceived != 0) 
       { 
        _log.AddInformation("Request resuming with range: {0} , {1}", totalBytesReceived, totalBytesToReceive); 
        request.AddRange(totalBytesReceived, totalBytesToReceive); 
       } 

       using (var response = request.GetResponse()) 
       { 
        _log.AddInformation("Received response. ContentLength={0} , ContentType={1}", response.ContentLength, response.ContentType); 

        if (totalBytesToReceive == 0) 
        { 
         totalBytesToReceive = response.ContentLength; 
        } 

        using (var responseStream = response.GetResponseStream()) 
        { 
         _log.AddInformation("Beginning read of response stream."); 
         var buffer = new byte[4096]; 
         int bytesRead = responseStream.Read(buffer, 0, buffer.Length); 
         while (bytesRead > 0) 
         { 
          fileStream.Write(buffer, 0, bytesRead); 
          totalBytesReceived += bytesRead; 
          bytesRead = responseStream.Read(buffer, 0, buffer.Length); 
         } 

         _log.AddInformation("Finished read of response stream."); 
        } 
       } 

       _log.AddInformation("Finished downloading file."); 
       isFinished = true; 
      } 
      catch (Exception ex) 
      { 
       _log.AddInformation("Response raised exception ({0}). {1}", ex.GetType(), ex.Message); 
      } 
     } 
    } 
} 

Ecco l'output del registro dal download corrotto:

Request #1. 
Received response. ContentLength=939302925 , ContentType=application/zip 
Beginning read of response stream. 
Response raised exception (System.Net.WebException). The operation has timed out. 
Request #2. 
Request resuming with range: 939295833 , 939302925 
Received response. ContentLength=7092 , ContentType=application/zip 
Beginning read of response stream. 
Finished read of response stream. 
Finished downloading file. 
+1

Potrei pensare a due cose in cima alla mia testa. a) Aumentare il timeout per i file di grandi dimensioni (se possibile) b) la codifica e la decodifica dei dati potrebbero essere danneggiati? Ho avuto questo problema su un progetto diverso che avevo una volta. Prova a codificarlo usando UTF-8 – Steven

+0

Non dovrebbe essere un problema di codifica, è un blob binario (file zip). – Spish

+5

Sembra che tu stia cercando di eseguire il debug di un bug del server sulla parte sbagliata del cavo. –

risposta

0

questo è il metodo che di solito uso, ma non mi ha fallito finora per lo stesso tipo di carico si ha bisogno. Prova ad usare il mio codice per cambiare un po 'il tuo e vedere se questo aiuta.

if (!Directory.Exists(localFolder)) 
{ 
    Directory.CreateDirectory(localFolder); 
} 


try 
{ 
    HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(Path.Combine(uri, filename)); 
    httpRequest.Method = "GET"; 

    // if the URI doesn't exist, exception gets thrown here... 
    using (HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse()) 
    { 
     using (Stream responseStream = httpResponse.GetResponseStream()) 
     { 
      using (FileStream localFileStream = 
       new FileStream(Path.Combine(localFolder, filename), FileMode.Create)) 
      { 
       var buffer = new byte[4096]; 
       long totalBytesRead = 0; 
       int bytesRead; 

       while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) > 0) 
       { 
        totalBytesRead += bytesRead; 
        localFileStream.Write(buffer, 0, bytesRead); 
       } 
      } 
     } 
    } 
} 
catch (Exception ex) 
{   
    throw; 
} 
0

È necessario modificare le impostazioni di timeout. Sembrano esserci due possibili problemi di timeout:

  • Timeout lato client: provare a modificare i timeout in WebClient. Trovo che per i download di file di grandi dimensioni a volte ho bisogno di farlo.
  • Timeout sul lato server: provare a modificare il timeout sul server. Puoi convalidare questo problema usando un altro client, ad es. PostMan
0

Per me il tuo metodo su come leggere il file tramite buffering sembra molto strano. Forse il problema è, che si fa

while(bytesRead > 0) 

Che cosa succede se, per qualche motivo, il flusso di doesnt restituisce alcun byte ad un certo punto, ma non è ancora ancora scaricano finito, allora sarebbe uscire dal ciclo e non tornare più indietro. Dovresti ottenere Content-Length e incrementare una variabile totalBytesReceived by bytesRead. Finalmente cambi il ciclo a

while(totalBytesReceived < ContentLength) 
Problemi correlati