175

我正在向要写入的方法发送一个流,并且在这些方法中我使用的是二进制读取器/写入器。当读取器/写入器被处理时,无论using是被引用还是仅仅在它未被引用时,流是否也关闭了?

我会发送一个 BinaryReader/Writer,但我也在使用 StreamReader(也许我应该绕过它。我只将它用于 GetLine 和 ReadLine)。如果每次关闭写入器/读取器时都关闭流,这将非常麻烦。

4

7 回答 7

215

是的,StreamReaderStreamWriterBinaryReader并且BinaryWriter都在您调用它们时关闭/处置它们的底层流Dispose。如果读取器/写入器只是被垃圾收集,它们不会处理流 - 您应该始终处理读取器/写入器,最好使用using语句。(事实上​​,这些类都没有终结器,也不应该有。)

就我个人而言,我也更喜欢对流使用 using 语句。您可以非常巧妙地嵌套using不带大括号的语句:

using (Stream stream = ...)
using (StreamReader reader = new StreamReader(stream, Encoding.Whatever))
{
}

即使using流的语句有些多余(除非StreamReader构造函数抛出异常),但我认为这是最佳实践,因为如果您摆脱了StreamReader并在以后直接使用流,您将已经有了正确的处置语义。

于 2009-06-30T18:23:10.393 回答
52

这是一个旧的,但我今天想做类似的事情,发现事情已经改变了。从 .net 4.5 开始,有一个leaveOpen论点:

public StreamReader( Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize, bool leaveOpen )

唯一的问题是为其他参数设置什么并不完全清楚。这里有一些帮助:

从StreamReader Constructor (Stream)的 msdn 页面:

此构造函数将编码初始化为 UTF8Encoding,使用流参数初始化 BaseStream 属性,并将内部缓冲区大小初始化为 1024 字节。

剩下的就是从源代码detectEncodingFromByteOrderMarks来看是true

public StreamReader(Stream stream)
        : this(stream, true) {
}

public StreamReader(Stream stream, bool detectEncodingFromByteOrderMarks)
        : this(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks, DefaultBufferSize) {
}

如果其中一些默认值被公开,或者参数是可选的,这样我们就可以指定我们想要的那些,那就太好了。

于 2014-01-12T04:55:13.787 回答
30

是的,它确实。您可以通过使用 Reflector 查看实现来验证这一点。

protected override void Dispose(bool disposing)
{
    try
    {
        if ((this.Closable && disposing) && (this.stream != null))
        {
            this.stream.Close();
        }
    }
    finally
    {
        if (this.Closable && (this.stream != null))
        {    
            this.stream = null;    
            this.encoding = null;
            this.decoder = null;
            this.byteBuffer = null;
            this.charBuffer = null;
            this.charPos = 0;
            this.charLen = 0;
            base.Dispose(disposing);
        }
    }
}
于 2009-06-30T18:22:51.437 回答
16

晚了六年,但也许这可能对某人有所帮助。

StreamReader 在释放时会关闭连接。但是,“使用 (Stream stream = ...){...}”和 StreamReader/StreamWriter 会导致 Stream 被释放两次:(1) 当 StreamReader 对象被释放时 (2) 和 Stream using 块时关闭。这会导致在运行 VS 的代码分析时出现 CA2202 警告。

另一种直接取自CA2202页面的解决方案是使用 try/finally 块。正确设置,这只会关闭一次连接。

在CA2202的底部附近,Microsoft 建议使用以下内容:

Stream stream = null;
try
{
    stream = new FileStream("file.txt", FileMode.OpenOrCreate);
    using (StreamWriter writer = new StreamWriter(stream))
    {
        stream = null;
        // Use the writer object...
    }
}
finally
{
    stream?.Dispose();
}

代替...

// Generates a CA2202 warning
using (Stream stream = new FileStream("file.txt", FileMode.Open))
using (XmlReader reader = new XmlReader (stream))
{
    // Use the reader object...
}
于 2015-09-13T21:11:21.870 回答
2

是的。调用 Dispose() 和 IDisposable(“使用”)应该使对象清理其所有资源。这包括刷新和关闭其文件描述符的流。

如果在您的情况下,您想将其传递给其他方法,那么您需要确保这些方法不会在 using 块中进行读取/写入。

于 2009-06-30T18:22:55.027 回答
1

如果需要,解决此问题的一种简单方法是重写 StreamWriter 类的 Dispose 方法。有关如何执行此操作的代码,请参见我的帖子:

.Disposing a StreamWriter 是否会关闭底层流?

于 2011-07-21T23:53:57.993 回答
-2

通过“使用”关键字或显式调用 dispose 处理的流

于 2009-06-30T18:22:04.230 回答