2016-08-19 48 views
4

我的程序使用HttpClient向Web API發送GET請求,並返回一個文件。我可以直接從HttpResponseMessage流沒有通過內存流文件?

我現在使用此代碼(簡化)將文件存儲到光盤:

public async Task<bool> DownloadFile() 
{ 
    var client = new HttpClient(); 
    var uri = new Uri("http://somedomain.com/path"); 
    var response = await client.GetAsync(uri); 

    if (response.IsSuccessStatusCode) 
    { 
     var fileName = response.Content.Headers.ContentDisposition.FileName; 
     using (var fs = new FileStream("C:\test\" + fileName, FileMode.Create, FileAccess.Write, FileShare.None)) 
     { 
      await response.Content.CopyToAsync(fs); 
      return true; 
     } 
    } 

    return false; 
} 

現在,此代碼運行時,該進程加載的所有文件到內存中。實際上,我更希望將流從HttpResponseMessage.Content流式傳輸到FileStream,以便只將其中一小部分保存在內存中。

我們正計劃在大文件(> 1GB)上使用它,那麼有沒有一種方法可以實現這一點,而不需要在內存中存儲所有文件?

理想情況下,無需手動循環讀取部分到byte []並將該部分寫入文件流,直到寫入所有內容爲止?

+0

看看 - https://msdn.microsoft.com/en-us/library/system.web.http.hosting.ihostbufferpolicyselector(v=vs.118).aspx –

+1

'CopyToAsync'已經在做你所描述的(在內部它反覆從響應中讀取一塊數據並將其寫入文件,直到所有數據都被傳輸),它不應該導致一次將整個文件緩存到內存。 – Iridium

+0

這就是我所想的,然而看着內存消耗,它確實會將整個文件加載到內存中,這是我想避免的。 –

回答

3

它看起來像這樣是設計 - 如果選中文檔HttpClient.GetAsync()你會看到它說:整個響應 後

返回的任務對象將完成(包括內容)讀

您可以改用HttpClient.GetStreamAsync()其中明確規定:

此方法不緩衝流。

但是,你不要然後訪問響應中的頭,據我所知。由於這可能是一項要求(因爲您從頭文件中獲得文件名),那麼您可能需要使用HttpWebRequest,而不是將整個響應讀入內存,從而獲得響應詳細信息(標題等)。喜歡的東西:

public async Task<bool> DownloadFile() 
{ 
    var uri = new Uri("http://somedomain.com/path"); 
    var request = WebRequest.CreateHttp(uri); 
    var response = await request.GetResponseAsync(); 

    ContentDispositionHeaderValue contentDisposition; 
    var fileName = ContentDispositionHeaderValue.TryParse(response.Headers["Content-Disposition"], out contentDisposition) 
     ? contentDisposition.FileName 
     : "noname.dat"; 
    using (var fs = new FileStream(@"C:\test\" + fileName, FileMode.Create, FileAccess.Write, FileShare.None)) 
    { 
     await response.GetResponseStream().CopyToAsync(fs); 
    } 

    return true 
} 

注意,如果請求返回不成功的響應代碼會拋出異常,因此你不妨在try..catch包裹在這種情況下返回false在你原來的例子。

+0

感謝您的澄清。事實上,在客戶端上使用GetStreamAsync允許將流直接保存到磁盤而不是內存。由於我們也可以控制服務器,所以我可以首先在單獨的請求中獲取元數據(文件名,大小)。然後我不需要訪問標題。 –

相關問題