2013-01-30 29 views
6

Trong ứng dụng của tôi, tôi có thể tải xuống một số tệp phương tiện từ web. Thông thường tôi đã sử dụng phương pháp WebClient.OpenReadCompleted để tải xuống, giải mã và lưu tệp vào IsolatedStorage. Nó hoạt động tốt và nhìn như thế:Tải xuống tệp theo khối (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 
       } 
      } 

Nhưng sau một cuộc điều tra tôi phát hiện ra rằng với các tập tin lớn (đối với tôi nó là hơn 100 MB) Tôi nhận được OutOfMemory ngoại lệ trong tải tập tin này. Tôi cho rằng đó là vì WebClient.OpenReadCompleted tải toàn bộ luồng vào RAM và cuộn cảm ... Và tôi sẽ cần thêm bộ nhớ để giải mã luồng này. Sau khi điều tra khác, tôi đã tìm thấy cách chia tập tin lớn thành các khối sau khi OpenReadCompleted sự kiện khi lưu tệp này vào IsolatedStorage (hoặc giải mã và sau đó lưu trong ocasion của tôi), nhưng điều này sẽ giúp chỉ với một phần của vấn đề. .. Vấn đề chính là cách ngăn chặn điện thoại bị gián đoạn trong quá trình tải xuống. Có cách nào để tải xuống tệp lớn theo khối không? Sau đó, tôi có thể sử dụng giải pháp tìm thấy để vượt qua quá trình giải mã. (Và tôi vẫn sẽ cần phải tìm một cách để tải tập tin lớn như vậy vào MediaElement, nhưng đó sẽ là một câu hỏi khác)


Trả lời:

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

bạn đã hỏi câu hỏi này? http://stackoverflow.com/questions/14600426/how-to-download-and-save-large-1gb-video-files-from-web-into-windows-phone-8/14602104#14602104 Hãy xem tôi đáp ứng –

+0

@Hermit, không có tôi thậm chí không nhận thấy rằng một, bởi vì tôi không có windows-phone-8 trong các thẻ yêu thích của tôi. Thật không may, câu trả lời của bạn không giúp tôi, về mặt lý thuyết tôi biết, những gì tôi nên làm :) Câu hỏi là "Làm thế nào?" – Olter

+0

có thể điều này sẽ giúp http://stackoverflow.com/questions/5659189/how-to-split-a-large-file-into-chunks-in-c –

Trả lời

4

Để tải về một tập tin trong khối bạn' sẽ cần phải thực hiện nhiều yêu cầu. Một cho mỗi đoạn.
Thật không may là không thể nói "lấy cho tôi tập tin này và trả lại trong các khối có kích thước X";

Giả sử máy chủ hỗ trợ nó, bạn có thể sử dụng tiêu đề HTTP Range để chỉ định byte nào của tệp mà máy chủ sẽ trả về theo yêu cầu.
Sau đó, bạn thực hiện nhiều yêu cầu để nhận tệp theo từng phần rồi đặt tất cả lại với nhau trên thiết bị. Có thể bạn sẽ thấy đơn giản nhất để thực hiện các cuộc gọi tuần tự và bắt đầu cuộc gọi tiếp theo khi bạn đã có và xác minh đoạn trước đó.

Cách tiếp cận này giúp dễ dàng tiếp tục tải xuống khi người dùng quay lại ứng dụng. Bạn chỉ cần nhìn vào bao nhiêu đã được tải về trước đó và sau đó nhận được đoạn tiếp theo.

Tôi đã viết một ứng dụng tải xuống phim (tối đa 2.6 GB) theo khối 64K và sau đó phát lại chúng từ IsolatedStorage với MediaPlayerLauncher. Chơi qua số MediaElement cũng sẽ hoạt động nhưng tôi chưa xác minh. Bạn có thể kiểm tra điều này bằng cách tải một tệp lớn trực tiếp vào IsolatedStorage (thông qua Isolated Storage Explorer hoặc tương tự) và kiểm tra các tác động của bộ nhớ khi chơi theo cách đó.

1

Xác nhận: Bạn có thể sử dụng BackgroundTransferRequest để download các file đa GB nhưng bạn phải thiết lập TransferPreferences-None để buộc các tải xảy ra khi kết nối với một nguồn cung cấp điện bên ngoài và khi kết nối với Wi-Fi, khác BackgroundTransferRequest sẽ Thất bại.


Tôi tự hỏi liệu có thể sử dụng BackgroundTransferRequest để tải xuống tệp lớn dễ dàng và để điện thoại lo lắng về chi tiết triển khai? Tài liệu này dường như gợi ý rằng tải xuống tệp trên 100 MB là có thể và động từ "Phạm vi" được dành riêng cho việc sử dụng riêng của nó, vì vậy nó có thể sử dụng tự động nếu nó có thể ở hậu trường.

Từ các tài liệu liên quan đến các file trên 100 MB:

Đối với các file lớn hơn 100 MB, bạn phải thiết lập các TransferPreferences tài sản của chuyển giao cho Không có hoặc việc chuyển giao sẽ thất bại. Nếu bạn làm không biết kích thước của quá trình chuyển và có thể vượt quá giới hạn này, bạn nên đặt giá trị thành Không, nghĩa là việc chuyển sẽ chỉ tiếp tục khi điện thoại được kết nối với điện thoại bên ngoài và có kết nối Wi-Fi.

Từ các tài liệu về việc sử dụng "Range" verb:

Thuộc tính Headers của đối tượng BackgroundTransferRequest được sử dụng để thiết lập các tiêu đề HTTP cho một yêu cầu chuyển nhượng. Các tiêu đề sau được dành riêng cho hệ thống sử dụng và không thể sử dụng bằng cách gọi ứng dụng. Thêm một trong các tiêu đề sau đây để thu Headers sẽ gây ra một NotSupportedException được ném khi phương thức Add (BackgroundTransferRequest) được sử dụng để xếp hàng yêu cầu chuyển :

  • If-Modified-Since
  • Nếu -None-Match
  • Nếu cấp
  • Phạm vi
  • Trừ-Modified-Since

Đây là tài liệu hướng dẫn: http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh202955(v=vs.105).aspx