在Silverlight中我们可以通过设置HttpWebRequest.AllowReadStreamBuffering为false,或者使用HttpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead)来实现在回调函数中不必等到Stream完全下载完成后才能读取数据,以便计算下载速度或进行其他处理。然而在WPRT应用中(WinRT未受影响)这两种方式都失去了效果,见示例:

string url = "http://abc";
HttpWebRequest hwr = (HttpWebRequest)HttpWebRequest.Create(new Uri(url));
hwr.AllowReadStreamBuffering = false;
hwr.BeginGetResponse(GetFileCallback, hwr);
 
private async void GetFileCallback(IAsyncResult asynchronousResult)
{
    HttpWebRequest request = (HttpWebRequest)(asynchronousResult.AsyncState);
    HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
    StorageFolder tempFolder = await ApplicationData.Current.LocalFolder.CreateFolderAsync("temp", CreationCollisionOption.OpenIfExists);
    StorageFile tempFlvFile = await tempFolder.CreateFileAsync("file.tmp ", CreationCollisionOption.ReplaceExisting);
 
    using (Stream streamResponse = response.GetResponseStream())
    {
        using (Stream fileStream = await tempFile.OpenStreamForWriteAsync())
        {
            Debug.WriteLine("file length:  " + response.ContentLength);
            byte[] bs = new byte[1024 * 1024];
            int size = streamResponse.Read(bs, 0, bs.Length);  // streamResponse被完全下载之前不返回; SL8.0和WinRT未受影响
            while (size >= 0)
            {
                // loop logical
            }
        }
    }
}

期望运行结果:

expected

实际运行结果:

actual

问题原因

通过和微软相关团队的沟通,得知这是一个已经确认的bug,不过暂时没有修复bug的预计时间。

解决方案

目前的替代方案是使用Windows.Web.Http.HttpClient:

HttpClient client = new HttpClient();
IInputStream stream = await client.GetInputStreamAsync(new Uri("http://video.ch9.ms/sessions/build/2014/2-517_LG.mp4"));
StorageFolder tempFolder = await ApplicationData.Current.LocalFolder.CreateFolderAsync("temp", CreationCollisionOption.OpenIfExists);
StorageFile tempFlvFile = await tempFolder.CreateFileAsync("file.tmp", CreationCollisionOption.ReplaceExisting);

using (Stream streamResponse = stream.AsStreamForRead())
{
    Stopwatch newWatch = new Stopwatch();
    newWatch.Start();

    using (Stream streamFile = await tempFlvFile.OpenStreamForWriteAsync())
    {
        int bytesRead = 0;
        byte[] myBuffer = new byte[1024 * 1024];

        while ((bytesRead = streamResponse.Read(myBuffer, 0, myBuffer.Length)) >= 0)
        {
            Debug.WriteLine(bytesRead.ToString() + " bytes read. Elapsed time: " + newWatch.Elapsed.TotalSeconds.ToString("0.000") + " seconds");
            streamFile.Write(myBuffer, 0, bytesRead);
        }
    }
}
» 转载请注明来源及链接:未来代码研究所

Related Posts:

Leave a Reply

World Line
Time Machine
Friendly Links
Online Tools