2016-12-02 140 views
0

我正在制作测试控制台应用程序,即使用URL下载流mp4。异步方法无法正常工作

我使用了MSDN上发布的异步示例。

以下是代码。

class Program 
{ 
    public static ManualResetEvent allDone = new ManualResetEvent(false); 
    const int BUFFER_SIZE = 1024; 
    public static int total = 0; 

    static void Main(string[] args) 
    { 

     Uri httpSite = new Uri("URI"); 

     WebRequest wreq = WebRequest.Create(httpSite); 

     RequestState rs = new RequestState(); 

     rs.Request = wreq; 

     IAsyncResult r = (IAsyncResult)wreq.BeginGetResponse(
      new AsyncCallback(RespCallback), rs); 

     allDone.WaitOne(); 
     FileStream file = new FileStream("test.mp4", FileMode.Append); 
     file.Write(rs.data.ToArray(), 0, rs.data.Count()); 
     Console.ReadKey(); 

    } 

    private static void RespCallback(IAsyncResult ar) 
    { 
     // Get the RequestState object from the async result. 
     RequestState rs = (RequestState)ar.AsyncState; 

     // Get the WebRequest from RequestState. 
     WebRequest req = rs.Request; 

     // Call EndGetResponse, which produces the WebResponse object 
     // that came from the request issued above. 
     WebResponse resp = req.EndGetResponse(ar); 

     // Start reading data from the response stream. 
     Stream ResponseStream = resp.GetResponseStream(); 

     // Store the response stream in RequestState to read 
     // the stream asynchronously. 
     rs.ResponseStream = ResponseStream; 

     // Pass rs.BufferRead to BeginRead. Read data into rs.BufferRead 
     IAsyncResult iarRead = ResponseStream.BeginRead(rs.BufferRead, 0, 
      BUFFER_SIZE, new AsyncCallback(ReadCallBack), rs); 
    } 
    private static void ReadCallBack(IAsyncResult asyncResult) 
    { 
     // Get the RequestState object from AsyncResult. 
     RequestState rs = (RequestState)asyncResult.AsyncState; 

     // Retrieve the ResponseStream that was set in RespCallback. 
     Stream responseStream = rs.ResponseStream; 

     // Read rs.BufferRead to verify that it contains data. 
     int read = responseStream.EndRead(asyncResult); 
     if (read > 0) 
     { 
      // Prepare a Char array buffer for converting to Unicode. 
      byte[] charBuffer = new byte[BUFFER_SIZE];    


      responseStream.Read(charBuffer, 0, read); 
      rs.data.AddRange(charBuffer); 


      IAsyncResult ar = responseStream.BeginRead(
       rs.BufferRead, 0, BUFFER_SIZE, 
       new AsyncCallback(ReadCallBack), rs); 
     } 
     else 
     {    
      responseStream.Close(); 
      // Set the ManualResetEvent so the main thread can exit. 
      allDone.Set(); 
     } 
     return; 
    } 
} 

当我使用这个异步方法时,保存的文件大小是1356KB,文件支持为2,409KB。

我可以发现IF(读> 0)语句中的断点在命中responseStream.close()的断点后被命中。这是因为它读了0的长度,然后阅读更多?

当我使用下面的非异步方法时,我可以成功下载该文件。

public static void StreamDownload(string url) 
    { 
     int dataLength; 
     int bytesRead; 

     WebRequest req = WebRequest.Create(url); 
     WebResponse response = req.GetResponse(); 
     string fileName = System.IO.Path.GetFileName("test.mp4"); 

     Stream dataStream = response.GetResponseStream(); 

     byte[] buffer = new byte[1024]; 

     FileStream file = new FileStream(fileName, FileMode.Append); 

     dataLength = (int)response.ContentLength; 

     do 
     { 
      bytesRead = dataStream.Read(buffer, 0, buffer.Length); 
      file.Write(buffer, 0, bytesRead); 

     } while (bytesRead != 0); 


    } 

没有人知道为什么我用异步方法失败吗?

感谢您的帮助。

回答

0

还有其他多种方式可以下载更简单的文件,你应该选择其中的一种。

webclient vs httpclient vs httpwebrequest

在你的情况我建议HttpClient的

public static async Task DownloadAsync(string requestUri, string filename) 
{ 
    using (var httpClient = new HttpClient()) 
    { 
     using (var fs = File.OpenWrite(filename)) 
     { 
      await (await httpClient.GetStreamAsync(requestUri)).CopyToAsync(fs); 
     } 
    } 
} 

或者你可以使用WebClient的类的DownloadFileAsync方法,如果你需要表现出一定的进步,但上面的例子比较简单。