【问题标题】:MemoryStream disables reading when returnedMemoryStream 返回时禁用读取
【发布时间】:2012-07-16 17:46:03
【问题描述】:

在我的程序中,我基本上是在读取一个文件,对其进行一些处理,然后将其作为内存流传递回主程序,这将由流读取器处理。这一切都将由我的主要课程旁边的一个班级处理。

问题是,当我从另一个类中的方法返回内存流时,“canread”变量设置为 false,从而导致流读取器初始化失败。

下面是发生问题的示例(尽管在这里我正在写入另一个类中的内存流,但是当我将其传回时它仍然会导致相同的错误。

在名为“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;
   }
}

主程序中的函数调用:

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

当我在“return MemStream”上设置断点时,“CanRead”属性仍然设置为 true。一旦我逐步返回到我的主函数,并将返回的值写入 MStream,“CanRead”属性设置为 false。这会导致 StreamReader 中出现异常,指出无法读取 MStream(如属性所示)。数据应该在流缓冲区中,但我就是无法将其取出。

如何设置它以便“CanRead”在返回到我的主目录后报告为真?还是我误解了 MemoryStream 的工作原理以及我将如何完成我想做的事情?

【问题讨论】:

    标签: c# stream memorystream


    【解决方案1】:

    正如其他人所说,问题是当 StreamWriter 关闭时 Stream 也关闭了。处理此问题的一种可能方法是返回字节数组而不是 MemoryStream。这避免了垃圾收集器必须处理的可能长时间运行的对象。

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

    另一种方法是在返回之前将 Stream 复制到另一个流。但是,这仍然存在后续使用 StreamReader 访问它会关闭该流的问题。

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

    【讨论】:

    • MemoryStream.ToArray() 甚至在底层 Stream 关​​闭时也可以工作。无法访问已关闭的流,但数据仍然存在。
    【解决方案2】:

    这就是问题所在:

    using (writer)
    {
        //Code that writes stuff to the memorystream via streamwriter
    
        return MemStream;
    }
    

    您正在关闭编写器,这将关闭MemoryStream。在这种情况下,您不想这样做……尽管您确实需要刷新编写器,然后倒回MemoryStream。只需将您的代码更改为:

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

    【讨论】:

    • Jon,如果 writer 在使用 stream 之前被 GC 会发生什么?
    • @KevinBrock:然后它只是垃圾收集,任何缓冲的数据都会丢失。 StreamWriter 没有终结器,AFAIK。
    • 就是这样。我认为返回它会在使用处理流写入器之前发送一个非封闭版本。我想我在想返回会返回 MemoryStream 的副本,而不是出于某种原因的引用。我还认为通过 return 离开 ImportantStreamManipulator 方法无论如何都会自动处理 streamwriter,所以我不确定这是否可能。流写入器会在稍后的某个时间通过 GC 在程序中被释放,还是仅在我释放 MemoryStream 或关闭程序后才被释放?
    • @Xantham:您不需要处理StreamWriter。它没有任何非托管资源。它将在最终使用后的任何时候被垃圾收集 - 可能直接在Flush 调用之后。
    【解决方案3】:

    StreamWriter 获得内存流的所有权,当using 语句结束时,MemoryStream 也关闭。

    Is there any way to close a StreamWriter without closing its BaseStream?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-04
      • 2018-12-17
      • 1970-01-01
      • 2023-03-30
      • 1970-01-01
      相关资源
      最近更新 更多