分块下载文件 (Windows Phone) [英] Download file in chunks (Windows Phone)

查看:21
本文介绍了分块下载文件 (Windows Phone)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In my application I can download some media files from web. Normally I used WebClient.OpenReadCompleted method to download, decrypt and save the file to IsolatedStorage. It worked well and looked like that:

 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 中并阻塞...而且我需要更多内存来解密这个流.

But after some investigation I found out that with large files(for me it's more than 100 MB) I'm getting OutOfMemory exception during downloading this file. I suppose that's because WebClient.OpenReadCompleted loads the whole stream into RAM and chokes... And I will need more memory to decrypt this stream.

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

After another investigation, I've found how to divide large file into chunks after OpenReadCompleted event at saving this file to IsolatedStorage(or decryption and then saving in my ocasion), but this would help with only a part of problem... The primary problem is how to prevent phone chokes during download process. Is there a way to download large file in chunks? Then I could use the found solution to pass through decryption process. (and still I'd need to find a way to load such big file into mediaElement, but that would be another question)

答案:

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

推荐答案

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

To download a file in chunks you'll need to make multiple requests. One for each chunk.
Unfortunately it's not possible to say "get me this file and return it in chunks of size X";

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

Assuming that the server supports it, you can use the HTTP Range header to specify which bytes of a file the server should return in response to a request.
You then make multiple requests to get the file in pieces and then put it all back together on the device. You'll probably find it simplest to make sequential calls and start the next one once you've got and verified the previous chunk.

这种方法使得在用户返回应用时恢复下载变得简单.您只需查看之前下载了多少,然后获取下一个块.

This approach makes it simple to resume a download when the user returns to the app. You just look at how much was downloaded previously and then get the next chunk.

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

I've written an app which downloads movies (up to 2.6GB) in 64K chunks and then played them back from IsolatedStorage with the MediaPlayerLauncher. Playing via the MediaElement should work too but I haven't verified. You can test this by loading a large file directly into IsolatedStorage (via Isolated Storage Explorer, or similar) and check the memory implications of playing that way.

这篇关于分块下载文件 (Windows Phone)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆