2012-01-05 3 views
39

Tôi đang trong quá trình soạn dịch vụ WCF cho phép trang web ASP.Net truy xuất tệp (dựa trên this article). Vấn đề của tôi là khi tôi trả lại luồng, nó trống.Trả lại luồng từ File.OpenRead()

Để đơn giản, tôi đã cô lập mã vào một ứng dụng winforms đơn giản để thử và tìm thấy những gì vấn đề là với trở về một dòng suối và đây là đoạn code:

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);      
    } 

Kết quả của mã này là buf dài 12,587 byte (độ dài chính xác của tệp) nhưng nó chỉ chứa 0.

Tài liệu Word mở ra không có vấn đề gì nếu tôi thử, tôi có thiếu điều gì đó hiển nhiên không?

+1

Bạn có phải là quản trị viên không? Hãy thử kéo tài liệu từ 'Tài liệu của tôi' hoặc một thư mục khác không phải là thư mục gốc. – keyboardP

+1

@keyboard - lời khuyên tốt nhưng nó sẽ tạo ra một ngoại lệ, không phải '0' và độ dài chính xác. –

+0

@ HenkHolterman - À vâng, đó là sự thật. – keyboardP

Trả lời

31

Bạn quên tìm kiếm:

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

Cảm ơn Ken, đã làm việc với nhau. – GrandMasterFlush

+0

nếu tìm kiếm không được phép thì sao? –

1

Hãy thử thay đổi mã của bạn như thế này:

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

Bạn cần

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

Và kể từ khi phương pháp Test() của bạn được bắt chước client nó nên đến Close() hoặc Dispose() số str S tream. Và cả MemoryStream nữa, chỉ ra khỏi hiệu trưởng.

+0

Cảm ơn Henk, điều đó đã hoạt động tốt. Các mã WCF sẽ đóng/xử lý các luồng cho phù hợp, tôi bỏ điều này ra trên các ứng dụng thử nghiệm. – GrandMasterFlush

+0

Tôi đã thu thập, nhưng điều đó làm cho nó trở thành ứng dụng thử nghiệm không đầy đủ. –

+0

Đồng ý, nhưng ứng dụng chỉ dành cho thử nghiệm/gỡ lỗi vấn đề, không phải là kiểm tra khai thác hoặc bất cứ điều gì liên quan đến bất kỳ thử nghiệm chính thức nào. Nó đã được dễ dàng hơn cho tôi để chuyển mã vào một ứng dụng đơn giản sau đó để thử và gỡ lỗi dịch vụ WCF trên máy chủ của nó. – GrandMasterFlush

12

Options:

  • Sử dụng data.Seek theo đề nghị của ken2k
  • Sử dụng hơi đơn giản Position tài sản:

    data.Position = 0; 
    
  • Sử dụng ToArray cuộc gọi trong MemoryStream để làm cho cuộc sống của bạn đơn giản để bắt đầu với:

    byte[] buf = data.ToArray(); 
    

Tùy chọn thứ ba sẽ là phương pháp ưa thích của tôi.

Lưu ý rằng bạn nên có một tuyên bố using để đóng dòng tập tin tự động (và tùy chọn cho MemoryStream), và tôi muốn thêm một chỉ thị sử dụng cho System.IO để làm cho mã sạch của bạn:

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

// Use buf 

Bạn cũng có thể muốn tạo phương thức tiện ích mở rộng trên Stream để thực hiện việc này cho bạn ở một nơi, ví dụ:

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

Lưu ý rằng này không đóng input stream.

+0

Cảm ơn Jon, đó là một cách tuyệt vời hơn để làm điều đó. Các WCF dịch vụ không sử dụng các báo cáo bằng cách sử dụng, tôi chỉ cần bỏ qua chúng từ mã kiểm tra để làm cho nó dễ dàng hơn để đọc khi tôi đăng nó trên đây. – GrandMasterFlush

5

Bạn quên để thiết lập lại vị trí của các dòng bộ nhớ:

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);      
} 

Cập nhật:

Có một điều nữa cần lưu ý: Nó thường trả tiền không bỏ qua các giá trị trở lại của phương pháp. Triển khai mạnh mẽ hơn nên kiểm tra số lượng byte đã đọc sau khi cuộc gọi trả về:

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)); 
    }      
}