2012-02-24 5 views
2

私は、Silverlightを使用してwp7で音楽プレーヤーを開発しています。私のエンドユーザーは、ローミング中にインターネットに接続できません。私は彼らに電話で音楽をダウンロードするオプションを与えたい。 これは、Wi-Fi接続があるときに音楽をダウンロードするために使用できるダウンロードマネージャーを書いています。 私は私が直面しているのは、私の音楽は私のサーバーに保存されており、私はWebCLientクラスを使って電話で音楽をダウンロードしています。 ファイルのサイズが68 MBを超えた場合、私のアプリケーションはOutOfMemory例外を受け取ります。 ここでコードである:WebClientを使用してWP7で大きなファイルを読み込んで保存する

公共ボイドDownloadKirtan(KirtanViewModel kirtanVm、BOOL QueueItem = TRUE){

 { 
      if (kirtanVm.LocationPath != null) 
      { 
       WebClient webClient = new WebClient(); 
       //webClient.AllowWriteStreamBuffering = false; 
       // webClient.AllowReadStreamBuffering = false; 
       if (QueueItem == false) 
       { 
        //App.ViewModel.ActiveInstancesOfWebClientForKirtanDownload[kirtanVm] = webClient; 
        // App.ViewModel.ActiveInstancesOfWebClientForKirtanDownload.Add(kirtanVm// 
        webClient = App.ViewModel.ActiveInstancesOfWebClientForKirtanDownload[kirtanVm]; 
        kirtanVm.IsDownloadedForOfflineViewing = "Started"; 
        webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(webClient_OpenReadCompleted); 
        webClient.OpenReadAsync(kirtanVm.LocationPath, kirtanVm); 
       } 
       else if (!App.ViewModel.ActiveInstancesOfWebClientForKirtanDownload.ContainsKey(kirtanVm)) 
       { 
        App.ViewModel.ActiveInstancesOfWebClientForKirtanDownload.Add(kirtanVm, webClient); 
        kirtanVm.IsDownloadedForOfflineViewing = "Started"; 
        webClient.OpenReadCompleted += new OpenReadCompletedEventHandler(webClient_OpenReadCompleted); 
        webClient.OpenReadAsync(kirtanVm.LocationPath, kirtanVm); 


       } 
       // webClient.DownloadProgressChanged += new DownloadProgressChangedEventHandler(webClient_DownloadProgressChanged); 

      } 
     } 
    } 

空隙webClient_OpenReadCompleted(オブジェクト送信者、OpenReadCompletedEventArgs E) {

 KirtanViewModel kirtanVm = e.UserState as KirtanViewModel; 
     try 
     { 
      if (e.Cancelled == false) 
      { 
       if (e.Result != null) 
       { 

        ((WebClient)sender).OpenReadCompleted -= webClient_OpenReadCompleted; 

        #region Isolated Storage Copy Code 


        IsolatedStorageFile isolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication(); 



        bool checkQuotaIncrease = IncreaseIsolatedStorageSpace(e.Result.Length); 


        if (checkQuotaIncrease) 
        { 

         string VideoFile = ""; 
         VideoFile = GetUrlOfOfflineContent(kirtanVm); 

         using (IsolatedStorageFileStream isolatedStorageFileStream = new IsolatedStorageFileStream(VideoFile, FileMode.Create, isolatedStorageFile)) 
         { 
          long VideoFileLength = (long)e.Result.Length; 


          byte[] byteImage = new byte[VideoFileLength]; 

          e.Result.Read(byteImage, 0, byteImage.Length); 

           isolatedStorageFileStream.Write(byteImage, 0, byteImage.Length); 


             kirtanVm.IsDownloadedForOfflineViewing = "True"; 
             kirtanVm.DownloadSize = "Size=" + (VideoFileLength/1000000).ToString() + " MB"; 
             kirtanVm.DownloadProgress = "100%"; 
             Settings.OfflineKirtanContents.Value.Add(kirtanVm); 
             AddRemoveKirtanInOfflineModels(kirtanVm, true); 





         } 

        #endregion 
        } 
        else 
        { 
         kirtanVm.IsDownloadedForOfflineViewing = "False"; 
         App.ViewModel.ActiveInstancesOfWebClientForKirtanDownload.Remove(kirtanVm); 
         MessageBox.Show("There is not enough space in your phone to store this media. You need " + e.Result.Length + " bytes of storage.Please free some offline contents you have downloaded by going to Offline content managemnt screen in Settings Section and try again or increase the storage on your phone."); 
        } 



        // mediaFile.SetSource(isolatedStorageFileStream); 

        // mediaFile.Play(); 

        // progressMedia.Visibility = Visibility.Collapsed; 





        } 
      } 

     } 

     catch (Exception ex) 
     { 
      kirtanVm.IsDownloadedForOfflineViewing = "Failed"; 

      //App.ViewModel.ActiveInstancesOfWebClientForKirtanDownload.Remove(kirtanVm); 
      MessageBox.Show(ex.ToString()); 

     } 

    } 

私が問題を抱えているのは、ストリームオブジェクトであるe.resultを取得したときです。 isolatedStoreFileStreamに書き込むには、それをバイト配列にもう一度読み込んで、それをisolatedstoragefileに保存する必要があります。これは非効率的で、2倍のメモリを消費します。 WebClient e.resultストリームオブジェクトによって60MBのメモリ(60MBファイル用)、配列に変換するために60MB。したがって、メモリ消費量は128 MBです。大きなファイルをダウンロードしてIsolatedStorageに保存するより良い方法はありますか?

更新:メモリ内のすべてを読み込むのではなく、チャンクサイズを使って以下のコードを使用しています。 MB

あなたはそれを一チューを記述する必要が無効webClient_OpenReadCompleted(オブジェクト送信者、OpenReadCompletedEventArgs E) {

 KirtanViewModel kirtanVm = e.UserState as KirtanViewModel; 
     try 
     { 
      if (e.Cancelled == false) 
      { 
       if (e.Result != null) 
       { 

        ((WebClient)sender).OpenReadCompleted -= webClient_OpenReadCompleted; 

        #region Isolated Storage Copy Code 
        bool checkQuotaIncrease = IncreaseIsolatedStorageSpace(e.Result.Length); 
        if (checkQuotaIncrease) 
        { 

         string VideoFile = ""; 
         VideoFile = GetUrlOfOfflineContent(kirtanVm); 
         ThreadPool.QueueUserWorkItem(k =>{ 
         using (IsolatedStorageFile isolatedStorageFile = IsolatedStorageFile.GetUserStoreForApplication()) 
         { 
          using (IsolatedStorageFileStream isolatedStorageFileStream = new IsolatedStorageFileStream(VideoFile, FileMode.Create, isolatedStorageFile)) 
          { 
           long VideoFileLength = (long)e.Result.Length; 


           using (BinaryWriter writer = new BinaryWriter(isolatedStorageFileStream)) 
           { 
            Stream resourceStream = e.Result;//streamResourceInfo.Stream; 
            long length = resourceStream.Length; 
            byte[] buffer = new byte[32]; 
            int readCount = 0; 
            using (BinaryReader reader = new BinaryReader(resourceStream)) 
            {     // read file in chunks in order to reduce memory consumption and increase performance      
             while (readCount < length) 
             { 
              int actual = reader.Read(buffer, 0, buffer.Length); 
              readCount += actual; 
              writer.Write(buffer, 0, actual); 
             } 
            } 
           } 
           kirtanVm.IsDownloadedForOfflineViewing = "True"; 
           kirtanVm.DownloadSize = "Size=" + (VideoFileLength/1000000).ToString() + " MB"; 
           kirtanVm.DownloadProgress = "100%"; 
           Settings.OfflineKirtanContents.Value.Add(kirtanVm); 
           AddRemoveKirtanInOfflineModels(kirtanVm, true); 
          } 
         } 
         }); 

           //byte[] byteImage = new byte[VideoFileLength]; 

           //e.Result.Read(byteImage, 0, byteImage.Length); 
           // e.re 
           //ThreadPool.QueueUserWorkItem(k =>{ 
           //  isolatedStorageFileStream.Write(byteImage, 0, byteImage.Length); 
           //isolatedStorageFileStream.Close(); 
           //Application.Current.RootVisual.Dispatcher.BeginInvoke(()=> 
           // { 
           //  kirtanVm.IsDownloadedForOfflineViewing = "True"; 
           //  kirtanVm.DownloadSize = "Size=" + (VideoFileLength/1000000).ToString() + " MB"; 
           //  kirtanVm.DownloadProgress = "100%"; 
           //  Settings.OfflineKirtanContents.Value.Add(kirtanVm); 
           //  AddRemoveKirtanInOfflineModels(kirtanVm, true); 
           // }); 

           //}); 
           //StreamWriter writer=new StreamWriter(isolatedStorageFileStream); 
           // writer.Write(e.Result); 
           // writer.Close(); 
           // isolatedStorageFileStream.Write(
           // e.Result.Write(

           // isolatedStorageFileStream.Write(byteImage, 0, byteImage.Length); 
           // isolatedStorageFileStream.Close(); 




          } 


        #endregion 

        else 
        { 
         kirtanVm.IsDownloadedForOfflineViewing = "False"; 
         App.ViewModel.ActiveInstancesOfWebClientForKirtanDownload.Remove(kirtanVm); 
         MessageBox.Show("There is not enough space in your phone to store this media. You need " + e.Result.Length + " bytes of storage.Please free some offline contents you have downloaded by going to Offline content managemnt screen in Settings Section and try again or increase the storage on your phone."); 
        } 

       } 
      } 
      else 
      { 
       lock (App.ViewModel.LockForCancelForCurrentOfflineDownload) 
       { 
        if (App.ViewModel.cancelInitiatedByUserForCurrentOfflineDownload) 
        { 
         kirtanVm.IsDownloadedForOfflineViewing = "False"; 
         // kirtanVm.IsOfflineDownloadCancelled = false; 
         App.ViewModel.cancelInitiatedByUserForCurrentOfflineDownload = false; 
        } 
        else 
        { 
         if (kirtanVm.IsDownloadedForOfflineViewing == "Started")// don't queue things again 
         { 
          kirtanVm.IsDownloadedForOfflineViewing = "Failed"; 
          // bool ItemExist = App.ViewModel.ActiveInstancesOfWebClientForKirtanDownload.Any(k => k.Key.Kirtan.KirtanId == kirtanVm.Kirtan.KirtanId); 

          DownloadKirtan(kirtanVm, false); 
         } 
        } 
       } 
      } 



     } 

     catch (Exception ex) 
     { 
      kirtanVm.IsDownloadedForOfflineViewing = "Failed"; 

      //App.ViewModel.ActiveInstancesOfWebClientForKirtanDownload.Remove(kirtanVm); 
      MessageBox.Show(ex.ToString()); 

     } 

    } 

おかげ Verinder

答えて

1

最後iはe.Result.Lengthに全てrefrencesを削除..私は ボイドwebClient_OpenReadCompleted(オブジェクト送信者、OpenReadCompletedEventArgs E){}の方法で、共有し、上記のコードでwebClient.AllowReadStreamBuffering = false;に溶液

ターンを発見。バッファリング・ソリューションを使用していないときは、事前にストリームサイズを知ることができない

long length = resourceStream.Length;          
byte[] buffer = new byte[1024];          
int readCount = 0;          
using (BinaryReader reader = new BinaryReader(resourceStream))          {     // read file in chunks in order to reduce memory consumption and increase performance                
while (true)           
{  
int actual = reader.Read(buffer, 0, 1024); 
if(actual==0) 
{ 
break; 
} 
else 
    {          
readCount += actual;            
writer.Write(buffer, 0, actual); 
}          
}          
} 

あなたが読んで行われていない限り、一度に1024バイトでストリームを読んでください。この方法でWebClientはメモリ内のファイル全体をバッファしませんし、携帯電話の最大mem使用量は一度に1KBになります。このようなデータのGigをダウンロードすることができます。高速に読み込みたい場合は、バッファサイズを1MBまたは3MBに増やしてください。 このコードをユーザスレッドの代わりにThreadPoolで実行することを確認してください

+0

です。long length = resourceStream.Length;間違いです。それを含めません –

0

は、あなたはデータを使い果たすまで、4KB(またはそれ)の配列に読み込んでそれを独立したストレージに書き込むことで、一度にnkを得ることができます。

+0

ちょうどそれを行うサンプルコードを教えてもらえますか? –

+0

私は小さなchunckサイズを使用してダウンロードを行うためにこのソリューションを使用しましたが、まだ100 MBのサイズの非常に大きなビデオのメモリエラーが発生します。コードは –

関連する問題