2012-01-05 29 views
39

我正在編寫一個WCF服務,它將允許ASP.Net網站檢索文件(基於this article)。我的問題是,當我返回流時,它是空白的。從File.OpenRead()返回一個流

爲簡單起見,我已經分離出的代碼放到一個簡單的WinForms應用程序,試圖找到問題是返回一個流什麼,這是代碼:

private Stream TestStream() 
    { 
     Stream fs = File.OpenRead(@"c:\testdocument.docx"); 
     return fs; 
    } 

    // This method converts the filestream into a byte array so that when it is 
    // used in my ASP.Net project the file can be sent using response.Write 
    private void Test() 
    {    
     System.IO.MemoryStream data = new System.IO.MemoryStream(); 
     System.IO.Stream str = TestStream(); 

     str.CopyTo(data); 
     byte[] buf = new byte[data.Length]; 
     data.Read(buf, 0, buf.Length);      
    } 

這段代碼的結果是, buf長度爲12,587字節(文件的正確長度),但它只包含0。

如果我嘗試使用Word文檔可以毫無問題地打開,我是否錯過了一些明顯的東西?

+1

您是否以管理員身份運行?嘗試從「我的文檔」或除root以外的其他文件夾中提取文檔。 – keyboardP 2012-01-05 11:13:46

+1

@keyboard - 很好的建議,但它會產生一個例外,而不是'0'和正確的長度。 – 2012-01-05 11:16:35

+0

@HenkHolterman - 是的,的確如此。 – keyboardP 2012-01-05 11:17:23

回答

31

你忘了求:

str.CopyTo(data); 
data.Seek(0, SeekOrigin.Begin); // <-- missing line 
byte[] buf = new byte[data.Length]; 
data.Read(buf, 0, buf.Length); 
+0

謝謝肯,那是一種享受。 – GrandMasterFlush 2012-01-05 11:28:34

+0

如果不允許尋找,該怎麼辦? – 2015-10-28 11:59:15

1

試着改變你的代碼如下:

private void Test() 
{    
    System.IO.MemoryStream data = new System.IO.MemoryStream(TestStream()); 

    byte[] buf = new byte[data.Length]; 
    data.Read(buf, 0, buf.Length);      
} 
3

你需要

str.CopyTo(data); 
    data.Position = 0; // reset to beginning 
    byte[] buf = new byte[data.Length]; 
    data.Read(buf, 0, buf.Length); 

而且,由於你的Test()方法模仿客戶端它應該到Close()Dispose()str S tream。而memoryStream也是,只是出於本質。

+0

謝謝Henk,那很好。 WCF代碼將相應地關閉/處理這些流,我在測試應用程序中放棄了這一點。 – GrandMasterFlush 2012-01-05 11:29:56

+0

我收集了,但這使得它不完整的測試應用程序。 – 2012-01-05 11:40:04

+0

同意,但該應用僅用於測試/調試問題,而不是測試用具或任何正式測試中涉及的任何內容。我更容易將代碼移植到一個簡單的應用程序中,然後嘗試在其服務器上調試WCF服務。 – GrandMasterFlush 2012-01-05 13:05:41

12

選項:

  • 使用data.Seek由ken2k
  • 使用建議稍微簡單Position屬性:

    data.Position = 0; 
    
  • 使用ToArray呼叫MemoryStream,使您的生活更簡單啓動與:

    byte[] buf = data.ToArray(); 
    

第三個選項將是我的首選方法。

注意,你應該有一個using語句自動關閉文件流(和可選的MemoryStream),我想補充一個using指令System.IO,使你的代碼更加清晰:

byte[] buf; 
using (MemoryStream data = new MemoryStream()) 
{ 
    using (Stream file = TestStream()) 
    { 
     file.CopyTo(data); 
     buf = data.ToArray(); 
    } 
} 

// Use buf 

你可能還需要在Stream上創建擴展方法,以便在一個地方爲您完成此操作,例如

public static byte[] CopyToArray(this Stream input) 
{ 
    using (MemoryStream memoryStream = new MemoryStream()) 
    { 
     input.CopyTo(memoryStream); 
     return memoryStream.ToArray(); 
    } 
} 

注意這關閉輸入流。

+0

感謝Jon,這是一個更好的方法。 WCF服務確實使用了使用語句,我只是從測試代碼中省略了它們,以便我在這裏發佈它時更易於閱讀。 – GrandMasterFlush 2012-01-05 11:34:54

5

你忘了復位內存流的位置:

private void Test() 
{    
    System.IO.MemoryStream data = new System.IO.MemoryStream(); 
    System.IO.Stream str = TestStream(); 

    str.CopyTo(data); 
    // Reset memory stream 
    data.Seek(0, SeekOrigin.Begin); 
    byte[] buf = new byte[data.Length]; 
    data.Read(buf, 0, buf.Length);      
} 

更新:

有一兩件事要注意:通常支付不能忽視的方法的返回值。更強大的實現應檢查通話返回後已讀取多少字節:

private void Test() 
{    
    using(MemoryStream data = new MemoryStream()) 
    { 
     using(Stream str = TestStream()) 
     { 
      str.CopyTo(data); 
     } 
     // Reset memory stream 
     data.Seek(0, SeekOrigin.Begin); 
     byte[] buf = new byte[data.Length]; 
     int bytesRead = data.Read(buf, 0, buf.Length); 

     Debug.Assert(bytesRead == data.Length, 
        String.Format("Expected to read {0} bytes, but read {1}.", 
         data.Length, bytesRead)); 
    }      
}