2017-04-12 106 views
0

我對流感到困惑,返回值和處置。即我使用Stream並想從方法返回流。下面的代碼:配置並返回值

public async Task<HttpResponseMessage> GetOverlayAsync(string fileUrl, string language, string strOCR) 
    { 
     HttpResponseMessage result = Request.CreateResponse(HttpStatusCode.OK); 
     using (var stream = new FileStream(@"D:\\_forTest.jpg", FileMode.Open)) 
     { 
      length = stream.Length; 
      result.Content = new StreamContent(stream); 
      result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment"); 
      result.Content.Headers.ContentDisposition.FileName = Path.GetFileName("_forTest.jpg"); 
      result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); 
      result.Content.Headers.ContentLength = length; 

      return result; 
     } 
    } 

public async Task<HttpResponseMessage> GetOverlayAsync(string fileUrl, string language, string strOCR) 
    { 
     long length = 0; 
     HttpResponseMessage result = Request.CreateResponse(HttpStatusCode.OK); 
     using (var stream = new FileStream(@"D:\\_forTest.jpg", FileMode.Open)) 
     { 
      length = stream.Length; 
      result.Content = new StreamContent(stream); 
     } 

     result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment"); 
     result.Content.Headers.ContentDisposition.FileName = Path.GetFileName("_forTest.jpg"); 
     result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); 
     result.Content.Headers.ContentLength = length; 

     return result; 

    } 

返回504狀態碼:

ReadResponse()失敗:服務器未返回爲此請求完全反應 。服務器返回0字節。

public async Task<HttpResponseMessage> GetOverlayAsync(string fileUrl, string language, string strOCR) 
    { 
     long length = 0; 
     HttpResponseMessage result = Request.CreateResponse(HttpStatusCode.OK); 
     var stream = new FileStream(@"D:\\_forTest.jpg", FileMode.Open); 
     length = stream.Length; 
     result.Content = new StreamContent(stream); 

     result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment"); 
     result.Content.Headers.ContentDisposition.FileName = Path.GetFileName("_forTest.jpg"); 
     result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); 
     result.Content.Headers.ContentLength = length; 

     return result; 
    } 

有時我得到的文件被阻止:

所以,按照我的理解,流當我們從法

出去如果我不調用Dispose在所有配置另一個過程。如何正確使用?

+0

你的例子是否真的編譯?這些方法被標記爲「async」,但方法中沒有「await」。 – Sean

+0

我在 –

+0

之前刪除了不必要的代碼嘗試打開文件流如下:'new FileStream(@「D:\\ _ forTest.jpg」,FileMode.Open,FileAccess.Read,FileShare.Read);'當然不要配置它(發送給客戶後會自動爲您處理)。當你只做'新的FileStream(...,FileMode.Open)' - 它相當於'新的FileStream(...,FileMode.Open,FileAccess.ReadWrite,FileShare。讀)「,並且這將防止隨後打開相同的文件,即使是來自相同的進程。 – Evk

回答

2

一些背景資料: 一般來說,如果你想流的文件的內容,你想要做的是從文件流讀取和寫入HTTP響應輸出流。 例子:現在

using (var source = new FileStream(...)) 
{ 
    byte[] buffer = new byte[4096]; 
    int byteCount; 
    while ((byteCount = await source.ReadAsync(buffer, 0, buffer.Length)) > 0) 
    { 
     await output.WriteAsync(buffer, 0, byteCount); 
    } 
} 

,你的具體情況,您使用的是框架/模式這需要您與您的內容傳遞流,而不是讓你寫到輸出自己。在這種情況下,您不得不將處置流的責任轉移到您的處理程序方法的調用者。

具體細節: 如果您的問題的文件被鎖定,那麼你可以允許共享的讀/寫訪問,當你打開流:

var stream = new FileStream(@"D:\\_forTest.jpg", FileMode.Open, FileAccess.Read, FileShare.ReadWrite); 

這將允許其它進程具有讀取和寫入在讀取文件時訪問文件。

編輯:正如@Evk指出,一個更安全的選擇是與讀者僅共享訪問(試圖打開並寫入文件將被拒絕):

var stream = new FileStream(@"D:\\_forTest.jpg", FileMode.Open, FileAccess.Read, FileShare.Read); 

改進: 如果你的文件適合在內存中,mem緩存而不是直接從磁盤進行流式傳輸將是明智之舉。如果您有數千個併發請求來獲取此文件,則您的磁盤將成爲一個巨大的瓶頸。使用具有保留/過期策略的緩存並讀取並緩存緩存未命中的整個文件。這樣,您還可以最小化文件句柄打開的窗口(打開,線性I/O讀取,關閉;非常快)。

+0

的確如此,但最好指定'FileShare.Read',因爲在閱讀過程中,您並不是真的想要有人在寫文件,而且在這種特殊情況下您並不需要這些。 – Evk

+0

好點,但要看。試圖更新文件時是否要阻止寫入?或者,如果某些用戶得到損壞的圖像,但是可以更新圖像而不停止服務器? –

+0

我認爲,如果「某些用戶得到了一個損壞的圖像」,它永遠不會確定:) :) – Evk