2012-07-17 36 views
9

Trong chương trình của tôi, về cơ bản tôi đang đọc trong một tệp, thực hiện một số xử lý, sau đó chuyển nó trở lại chương trình chính dưới dạng bộ nhớ, sẽ được xử lý bởi trình tạo luồng. Tất cả điều này sẽ được xử lý bởi một lớp bên cạnh chính của tôi.MemoryStream vô hiệu hóa đọc khi trả về

Vấn đề là, khi tôi trả về luồng bộ nhớ từ phương thức của tôi trong một lớp khác, biến "canread" được đặt thành false, và do đó khiến khởi tạo luồng không thành công.

Dưới đây là một ví dụ về các vấn đề xảy ra (mặc dù ở đây tôi đang viết để MemoryStream trong lớp khác, nhưng nó vẫn gây ra lỗi tương tự khi tôi vượt qua nó trở lại.

Trong lớp có tên là " Otherclass ":

public static MemoryStream ImportantStreamManipulator() 
{ 
    MemoryStream MemStream = new MemoryStream(); 

    StreamWriter writer = new StreamWriter(MemStream); 
    using (writer) 
    { 
     //Code that writes stuff to the memorystream via streamwriter 

     return MemStream; 
    } 
} 

chức năng gọi trong chương trình chính:

MemoryStream MStream = Otherclass.ImportantStreamManipulator(); 
StreamReader reader = new StreamReader(MStream); 

Khi tôi đặt một breakpoint trên "return MemStream", các "CanRead" bất động sản vẫn là đặt thành true. Khi tôi bước như vậy mà nó được trở lại chức năng chính của tôi, và viết giá trị trả về cho MStream, thuộc tính "CanRead" được đặt thành false. Điều này sau đó gây ra một ngoại lệ trong StreamReader nói rằng MStream không thể đọc được (như là thuộc tính được chỉ ra). Dữ liệu nằm trong bộ đệm luồng như nó nên, nhưng tôi không thể lấy nó ra.

Làm cách nào để đặt nó để "CanRead" sẽ báo cáo đúng khi nó được trả về chính của tôi? Hay tôi hiểu nhầm về cách thức hoạt động của MemoryStream và làm cách nào để hoàn thành những gì tôi muốn làm?

Trả lời

21

Đây là vấn đề:

using (writer) 
{ 
    //Code that writes stuff to the memorystream via streamwriter 

    return MemStream; 
} 

Bạn đang đóng cửa nhà văn, mà đóng MemoryStream. Trong trường hợp này bạn không muốn làm điều đó ... mặc dù bạn cần phải tuôn ra người viết và tua lại MemoryStream. Chỉ cần thay đổi mã của bạn thành:

public static MemoryStream ImportantStreamManipulator() 
{ 
    // Probably add a comment here stating that the lack of using statements 
    // is deliberate. 
    MemoryStream stream = new MemoryStream(); 

    StreamWriter writer = new StreamWriter(stream); 
    // Code that writes stuff to the memorystream via streamwriter 

    writer.Flush(); 
    stream.Position = 0; 
    return stream; 
} 
+0

Jon, điều gì sẽ xảy ra nếu 'writer' là GC trước khi' luồng' được sử dụng? –

+2

@KevinBrock: Sau đó, nó chỉ là rác thu thập được, và bất kỳ dữ liệu đệm bị mất. 'StreamWriter' không có trình hoàn thiện, AFAIK. –

+0

Đó là chính xác nó. Tôi nghĩ rằng trả lại nó sẽ gửi một phiên bản không đóng trước khi sử dụng sẽ xử lý của các nhà viết kịch bản. Tôi nghĩ rằng tôi đã nghĩ rằng sự trở lại sẽ trả về một bản sao của MemoryStream, không phải là một tham chiếu cho một số lý do.Tôi cũng nghĩ rằng việc rời khỏi phương thức ImportantStreamManipulator thông qua một sự trả về sẽ tự động loại bỏ các streamwriter anyway, vì vậy tôi đã không chắc chắn điều này là có thể. Liệu các nhà soạn nhạc sẽ được xử lý đôi khi sau này trong chương trình thông qua GC, hoặc nó sẽ chỉ được xử lý một khi tôi vứt bỏ MemoryStream hoặc đóng chương trình? – Xantham

0

Như những người khác đã nêu, vấn đề là luồng được đóng khi StreamWriter bị đóng. Một cách có thể để giải quyết vấn đề này là trả về một mảng byte thay vì một MemoryStream. Điều này tránh các đối tượng chạy dài có khả năng phải được xử lý bởi bộ thu gom rác.

public static void Main() 
{ 
    OutputData(GetData()); 
} 

public static byte[] GetData() 
{ 
    byte[] binaryData = null; 

    using (MemoryStream ms = new MemoryStream()) 
    using (StreamWriter sw = new StreamWriter(ms)) 
    { 
     string data = "My test data is really great!"; 

     sw.Write(data); 
     sw.Flush(); 

     binaryData = ms.ToArray(); 
    } 

    return binaryData; 
} 

public static void OutputData(byte[] binaryData) 
{ 
    using (MemoryStream ms = new MemoryStream(binaryData)) 
    using (StreamReader sr = new StreamReader(ms)) 
    { 
     Console.WriteLine(sr.ReadToEnd()); 
    } 
} 

Phương pháp khác là sao chép Luồng sang luồng khác trước khi quay lại. Tuy nhiên, điều này vẫn còn có vấn đề rằng truy cập tiếp theo nó với một StreamReader sẽ đóng luồng đó.

public static void RunSnippet() 
{ 
    OutputData(GetData()); 
} 

public static MemoryStream GetData() 
{ 
    MemoryStream outputStream = new MemoryStream(); 

    using (MemoryStream ms = new MemoryStream()) 
    using (StreamWriter sw = new StreamWriter(ms)) 
    { 
     string data = "My test data is really great!"; 

     sw.Write(data); 
     sw.Flush(); 

     ms.WriteTo(outputStream); 
     outputStream.Seek(0, SeekOrigin.Begin); 
    } 

    return outputStream; 
} 

public static void OutputData(MemoryStream inputStream) 
{ 
    using (StreamReader sr = new StreamReader(inputStream)) 
    { 
     Console.WriteLine(sr.ReadToEnd()); 
    } 
} 
Các vấn đề liên quan