【问题标题】:Download file in chunks (Windows Phone)分块下载文件(Windows Phone)
【发布时间】:2013-01-14 03:52:36
【问题描述】:

在我的应用程序中,我可以从网络下载一些媒体文件。通常我使用 WebClient.OpenReadCompleted 方法来下载、解密并将文件保存到 IsolatedStorage。它运行良好,看起来像这样:

 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
                 }
           }

但经过一番调查,我发现对于大文件(对我来说超过 100 MB),我在下载此文件时遇到 OutOfMemory 异常。我想那是因为 WebClient.OpenReadCompleted 将整个流加载到 RAM 中并阻塞......而且我需要更多内存来解密这个流。

经过另一次调查,我发现如何在 OpenReadCompleted 事件后将此文件保存到独立存储(或解密然后保存在我的情况下)后将大文件分成块,但这只会帮助解决部分问题.. . 主要问题是如何在下载过程中防止手机阻塞有没有办法分块下载大文件?然后我可以使用找到的解决方案通过解密过程。 (我仍然需要找到一种方法将这么大的文件加载到 mediaElement 中,但这将是另一个问题)


答案:

 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));
                                }
                            }
                        }
                    }
                }
            }

【问题讨论】:

  • 你问过这个问题吗? stackoverflow.com/questions/14600426/…看看我的回复
  • @Hermit,不,我什至没有注意到那个,因为我最喜欢的标签中没有 windows-phone-8。不幸的是,你的回答对我没有帮助,理论上我知道,我应该怎么做:) 问题是“如何?”
  • 也许这会有所帮助stackoverflow.com/questions/5659189/…
  • 不,那是文件传输系统,我无法控制文件传输。它应该是来自原生 WP7 类的一些方法,如 WebClient 或 httpwebrequest 或其他。
  • 没有股票类/方法做你想做的事。如果你想使用夹头,你将不得不四处寻找解决方案。

标签: c# windows-phone-7 download chunking


【解决方案1】:

要分块下载文件,您需要发出多个请求。每个块一个。
不幸的是,不能说“给我这个文件并以 X 大小的块返回它”;

假设服务器支持它,您可以使用 HTTP Range 标头来指定服务器应返回文件的哪些字节以响应请求。
然后,您发出多个请求以获取文件,然后将它们全部重新组合到设备上。您可能会发现,在获得并验证了前一个块后,进行顺序调用并开始下一个调用是最简单的。

这种方法可以在用户返回应用时轻松恢复下载。您只需查看之前下载了多少,然后获取下一个块。

我编写了一个应用程序,它以 64K 块下载电影(最大 2.6GB),然后使用 MediaPlayerLauncher 从独立存储中播放它们。通过MediaElement 播放也应该可以,但我还没有验证。您可以通过将大文件直接加载到独立存储(通过独立存储资源管理器或类似方法)来测试这一点,并检查以这种方式播放的内存影响。

【讨论】:

    【解决方案2】:

    确认:您可以使用BackgroundTransferRequest 下载多GB 文件,但您必须将TransferPreferences 设置为None 以强制在连接到外部电源时进行下载,同时连接到 wi-fi,否则BackgroundTransferRequest 将失败。


    我想知道是否可以使用BackgroundTransferRequest轻松下载大文件并让手机担心实现细节?文档似乎表明可以下载超过 100 MB 的文件,并且“范围”动词保留供自己使用,因此如果可以在幕后,它可能会自动使用它。

    来自有关超过 100 MB 文件的文档:

    对于大于 100 MB 的文件,您必须设置 TransferPreferences 转移到 None 或转移将失败。如果你这样做 不知道转移的大小,它有可能 超过此限制,您应该将该值设置为 None,这意味着 只有当手机连接到外部时才会进行传输 电源并有 Wi-Fi 连接。

    来自有关使用“范围”动词的文档:

    使用了 BackgroundTransferRequest 对象的 Headers 属性 设置传输请求的 HTTP 标头。以下标题 保留给系统使用,不能通过调用使用 应用程序。将以下标头之一添加到标头 集合将导致 NotSupportedException 被抛出时 Add(BackgroundTransferRequest) 方法用于对传输进行排队 请求:

    • If-Modified-Since
    • 如果没有匹配
    • If 范围
    • 范围
    • 除非修改自

    这是文档: http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh202955(v=vs.105).aspx

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多