MemoryStream - 无法访问已关闭的流

116

你好,为什么使用 using (var sw = new StreamWriter(ms)) 后会抛出 Cannot access a closed Stream 异常。在代码的顶部是一个 Memory Stream

using (var ms = new MemoryStream())
{
    using (var sw = new StreamWriter(ms))
    {                 
        sw.WriteLine("data");
        sw.WriteLine("data 2");
        ms.Position = 0;
        using (var sr = new StreamReader(ms))
        {
            Console.WriteLine(sr.ReadToEnd());                        
        }
    } //error here
}

如何最好地修复它? 谢谢


这可能是因为您正在从同一个MemoryStream创建StreamWriter和StreamReader。您可以尝试使用两个不同的MemoryStreams:一个用于读取,另一个用于写入。 - NKamrath
可能是重复的问题,参考链接:https://dev59.com/S3E95IYBdhLWcg3wY89l - Be Brave Be Like Ukraine
在某些情况下,一种解决方案可以基于创建一个新的MemoryStream,该新流使用关闭内存流上的MemoryStream.GetBuffer()。参见:https://dev59.com/5Gkw5IYBdhLWcg3w_fiJ#50671919 - RenniePet
7个回答

149
这是因为 StreamReader 在被处理时会自动关闭底层流。使用 using 语句可以自动完成这个操作。
然而,你正在使用的 StreamWriter 仍在尝试对流进行操作(同时,写入器的 using 语句现在也在尝试处理 StreamWriter 并关闭流)。
解决此问题的最佳方法是:不使用 using,也不要处理 StreamReaderStreamWriter。参见此问题
using (var ms = new MemoryStream())
{
    var sw = new StreamWriter(ms);
    var sr = new StreamReader(ms);

    sw.WriteLine("data");
    sw.WriteLine("data 2");
    ms.Position = 0;

    Console.WriteLine(sr.ReadToEnd());                        
}

如果你担心在你的代码中,swsr没有被正确释放(如建议的那样),而导致被垃圾回收,你可以这样做:

StreamWriter sw = null;
StreamReader sr = null;

try
{
    using (var ms = new MemoryStream())
    {
        sw = new StreamWriter(ms);
        sr = new StreamReader(ms);

        sw.WriteLine("data");
        sw.WriteLine("data 2");
        ms.Position = 0;

        Console.WriteLine(sr.ReadToEnd());                        
    }
}
finally
{
    if (sw != null) sw.Dispose();
    if (sr != null) sr.Dispose();
}

毫无疑问,我认为这就是为什么 OP 问“最好的修复方法是什么?”的原因。 - Austin Salonen
关于 close var sw = new StreamWriter(ms); var sr = new StreamReader(ms); 呢? - Arbejdsglæde
1
你不需要担心它们。我引用了我链接的问题中被接受的答案:如果您需要直接使用底层流,请放心让StreamReader超出范围。只需确保在适当时手动处理底层流即可。 换句话说:只要读取器和写入器没有被显式地处理,它们最终将被垃圾回收。但我会再次编辑以提供另一个可能的解决方案。 - Thorsten Dittmar
这段代码对我来说没有起作用。与“leaveOpen”答案相比,它没有起作用。或者需要使用.Flush() - Jaider

44

从 .net45 开始,你可以使用 StreamWriterLeaveOpen 构造函数参数,并仍然使用 using 语句。例如:

using (var ms = new MemoryStream())
{
    using (var sw = new StreamWriter(ms, leaveOpen:true))
    {
        sw.WriteLine("data");
        sw.WriteLine("data 2");    
    }

    ms.Position = 0;
    using (var sr = new StreamReader(ms))
    {
        Console.WriteLine(sr.ReadToEnd());
    }
}

1
+1 表示提及,也可以在不使用 "using" 语句的情况下使用。 (我的基础 MemoryStream 需要保持活动状态),而 -1 则是针对微软强制我使用那个丑陋构造函数的评价。^^ - Jan
2
@Jan,你可以使用new StreamWriter(ms, leaveOpen:true),我想这样会好看一些。 - Giannis Paraskevopoulos
这段代码有效。https://dotnetfiddle.net/jTYGak - Jaider

9

当你的StreamReader使用using()结束时,它会处理对象并关闭流,而你的StreamWriter仍在尝试使用该流。


4
毫无疑问,我认为这就是为什么OP问“修复它的最佳方法是什么?”的原因。 - Austin Salonen

2

当代码执行完使用语句后,Dispose方法会自动调用并关闭流。

请尝试以下操作:

using (var ms = new MemoryStream())
{
    var sw = new StreamWriter(ms);

        sw.WriteLine("data");
        sw.WriteLine("data 2");
        ms.Position = 0;
        using (var sr = new StreamReader(ms))
        {
            Console.WriteLine(sr.ReadToEnd());
        }
}    

1

要能够读取流,必须保持其处于打开状态。 “StreamWriter”在完成写入后会将其关闭。

using (var ms = new MemoryStream())
{
    using (var sw = new StreamWriter(ms, leaveOpen: true)))
    {                 
        sw.WriteLine("data");
        sw.WriteLine("data 2");
        ms.Position = 0;
        using (var sr = new StreamReader(ms))
        {
            Console.WriteLine(sr.ReadToEnd());                        
        }
    } //error here
}

1
问题出在这个块:
using (var sr = new StreamReader(ms))
{
    Console.WriteLine(sr.ReadToEnd());                        
}

StreamReader关闭(离开using后),它也会关闭其底层流,因此现在MemoryStream已关闭。当StreamWriter关闭时,它尝试将所有内容刷新到MemoryStream,但它已关闭。

您应该考虑不将StreamReader放在using块中。


0
在我的情况下(诚然非常神秘,不太可能经常出现),这是导致问题的原因(此代码与使用iTextSharp生成PDF有关):
PdfPTable tblDuckbilledPlatypi = new PdfPTable(3);
float[] DuckbilledPlatypiRowWidths = new float[] { 42f, 76f };
tblDuckbilledPlatypi.SetWidths(DuckbilledPlatypiRowWidths);

声明一个3列的表格,然后只为宽度设置了两个值,这似乎是问题的原因。一旦我将 "PdfPTable(3)" 改为 "PdfPTable(2)",问题就像传统烤箱一样消失了。

这应该是另一个问题和答案。它与 OP 的问题无关。虽然对于 iTextSharp 用户来说可能非常有用,但您提供帮助的方式是错误的(将其放入只有类似异常文本的随机问题中)。 - Sinatr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接