2013-01-30 5 views
6

In meiner Anwendung kann ich einige Mediendateien aus dem Internet herunterladen. Normalerweise verwende ich WebClient.OpenReadCompleted Methode zum Herunterladen, Entschlüsseln und Speichern der Datei zu IsolatedStorage. Es funktionierte gut und sah wie folgt aus:Datei in Stücke herunterladen (Windows Phone)

private void downloadedSong_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e, SomeOtherValues someOtherValues) // delegate, uses additional values 
     { 
      // Some preparations 

       try 
       { 
        if (e.Result != null) 
        { 
        using (isolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication()) 
        { 
         // working with the gained stream, decryption 
         // saving the decrypted file to isolatedStorage 
         isolatedStorageFileStream = new IsolatedStorageFileStream("SomeFileNameHere", FileMode.OpenOrCreate, isolatedStorageFile); 
         // and use it for MediaElement 
         mediaElement.SetSource(isolatedStorageFileStream); 
         mediaElement.Position = new TimeSpan(0); 
         mediaElement.MediaOpened += new RoutedEventHandler(mediaFile_MediaOpened); 

         // and some other work 
        } 
        } 
       } 
       catch(Exception ex) 
       { 
        // try/catch stuff 
       } 
      } 

Aber nach einiger Untersuchung fand ich heraus, dass mit großen Dateien (für mich ist es mehr als 100 MB ist) Ich bin immer OutOfMemory Ausnahme während diese Datei herunterzuladen. Ich nehme an, dass, weil WebClient.OpenReadCompleted den gesamten Strom in RAM und Drosseln lädt ... Und ich werde mehr Gedächtnis benötigen, um diesen Strom zu entschlüsseln.

Nach einer anderen Untersuchung, habe ich gefunden, wie große Datei in Stücke nach OpenReadCompleted Ereignis beim Speichern dieser Datei zu IsolatedStorage (oder Entschlüsselung und dann speichern in meinem Fall), aber dies würde nur mit einem Teil des Problems helfen. .. Das primäre Problem ist , wie Telefondrosseln während Download-Prozess zu verhindern. Gibt es eine Möglichkeit, große Dateien in Chunks herunterzuladen? Dann könnte ich die gefundene Lösung verwenden, um den Entschlüsselungsprozess zu durchlaufen. (Und noch würde ich brauche einen Weg zu finden, so große Datei in Mediaelement zu laden, aber das wäre eine andere Frage sein)


Antwort:

private WebHeaderCollection headers; 
private int iterator = 0; 
private int delta = 1048576; 
private string savedFile = "testFile.mp3"; 

// some preparations 
// Start downloading first piece 


using (IsolatedStorageFile isolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication()) 
        { 
         if (isolatedStorageFile.FileExists(savedFile)) 
          isolatedStorageFile.DeleteFile(savedFile); 
        } 

        headers = new WebHeaderCollection(); 
        headers[HttpRequestHeader.Range] = "bytes=" + iterator.ToString() + '-' + (iterator + delta).ToString(); 
        webClientReadCompleted = new WebClient(); 
        webClientReadCompleted.Headers = headers; 
        webClientReadCompleted.OpenReadCompleted += downloadedSong_OpenReadCompleted; 
        webClientReadCompleted.OpenReadAsync(new Uri(song.Link)); 
        // song.Link was given earlier 

private void downloadedSong_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e) 
     { 
      try 
      { 
       if (e.Cancelled == false) 
       { 
        if (e.Result != null) 
        { 
         ((WebClient)sender).OpenReadCompleted -= downloadedSong_OpenReadCompleted; 

         using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication()) 
         { 
          using (IsolatedStorageFileStream fileStream = new IsolatedStorageFileStream(savedFile, FileMode.Append, FileAccess.Write, myIsolatedStorage)) 
          { 
           int mediaFileLength = (int)e.Result.Length; 
           byte[] byteFile = new byte[mediaFileLength]; 
           e.Result.Read(byteFile, 0, byteFile.Length); 
           fileStream.Write(byteFile, 0, byteFile.Length); 

           // If there's something left, download it recursively 
           if (byteFile.Length > delta) 
           { 
            iterator = iterator + delta + 1; 

            headers = new WebHeaderCollection(); 
            headers[HttpRequestHeader.Range] = "bytes=" + iterator.ToString() + '-' + (iterator + delta).ToString(); 
            webClientReadCompleted.Headers = headers; 
            webClientReadCompleted.OpenReadCompleted += downloadedSong_OpenReadCompleted; 
            webClientReadCompleted.OpenReadAsync(new Uri(song.Link)); 
           } 
          } 
         } 
        } 
       } 
      } 
+0

Sie diese Frage stellen haben? http://stackoverflow.com/questions/14600426/how-to-download-and-save-large-1gb-video-files-from-web-into-windows-phone-8/14602104#14602104 Werfen Sie einen Blick auf meine Antwort –

+0

@Hermit, nein, ich habe das nicht einmal bemerkt, weil ich Windows-Phone-8 nicht in meinen Lieblings-Tags habe. Leider hilft mir deine Antwort nicht, theoretisch weiß ich, was ich tun soll :) Die Frage ist "Wie?" – Olter

+0

vielleicht hilft das http://stackoverflow.com/questions/5659189/how-to-split-a-large-file-into-chunks-in-c –

Antwort

4

Um eine Datei in Stücke downloaden Sie‘ Ich muss mehrere Anfragen stellen. Eine für jeden Brocken.
Leider ist es nicht möglich zu sagen: "Hol mir diese Datei und gib sie in Chunks der Größe X zurück";

Wenn der Server dies unterstützt, können Sie mithilfe des Headers HTTP Range angeben, welche Bytes einer Datei der Server als Antwort auf eine Anforderung zurückgeben soll.
Sie machen dann mehrere Anfragen, um die Datei in Stücke zu bekommen und dann alles wieder zusammen auf dem Gerät zu setzen. Sie werden es wahrscheinlich am einfachsten finden, sequenzielle Anrufe zu tätigen und den nächsten zu starten, sobald Sie den vorherigen Chunk verifiziert und verifiziert haben.

Dieser Ansatz macht es einfach, einen Download fortzusetzen, wenn der Benutzer zur App zurückkehrt. Sie sehen nur, wie viel vorher heruntergeladen wurde und dann den nächsten Brocken bekommen.

Ich habe eine App geschrieben, die Filme (bis zu 2,6 GB) in 64K Chunks herunterlädt und sie dann von IsolatedStorage mit der MediaPlayerLauncher wiedergibt. Spielen über die MediaElement sollte auch funktionieren, aber ich habe nicht verifiziert. Sie können dies testen, indem Sie eine große Datei direkt in IsolatedStorage laden (über den Isolated Storage Explorer o.ä.) und die Speicherauswirkungen auf diese Weise überprüfen.

1

Bestätigt: Sie BackgroundTransferRequest verwenden können Multi-GB-Dateien herunterladen, aber Sie TransferPreferences-None zu zwingen, um den Download zu passieren, während eine Verbindung mit einer externen Stromversorgung und während der Verbindung mit Wi-Fi, sonst die BackgroundTransferRequest setzen müssen werden Scheitern.


Ich frage mich, ob es möglich ist, eine Background zu verwenden, um große Dateien einfach und lassen Sie das Telefon Sorgen über die Details der Implementierung zum Download? Die Dokumentation scheint nahe zu legen, dass Dateidownloads über 100 MB möglich sind, und das Verb "Range" ist für den eigenen Gebrauch reserviert, also wird es wahrscheinlich automatisch verwendet, wenn es hinter den Kulissen möglich ist.

Aus der Dokumentation in Bezug auf Dateien über 100 MB:

Für Dateien, die größer als 100 MB, müssen Sie die TransferPreferences Eigenschaft der Übertragung auf keine festgelegt oder die Übertragung fehl. Wenn Sie nicht wissen, die Größe einer Übertragung und es ist möglich, dass diese Grenze überschreiten können, sollten Sie den Wert auf Keine setzen, was bedeutet, dass die Übertragung wird nur fortgesetzt, wenn das Telefon an externe Macht angeschlossen ist und hat eine Wi-Fi-Verbindung.

Aus der Dokumentation zur Nutzung des „Range“ Verbs:

Die Header-Eigenschaft des Objekts Background verwendet wird die HTTP-Header für eine Übertragungsanforderung zu setzen. Die folgenden Header sind für die Verwendung durch das System reserviert und können nicht durch Aufruf von Anwendungen verwendet werden. Hinzufügen eines der folgenden Überschriften zu den Headern Sammlung verursacht eine NotSupportedException geworfen werden, wenn die Add (Background) Verfahren verwendet wird, um die Übertragung Anfrage in die Warteschlange:

  • If-Modified-Since
  • Wenn -Keine-Match
  • Wenn Range
  • Bereich
  • Sofern-Modified-Since

Hier ist die Dokumentation: http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh202955(v=vs.105).aspx