处理streamreader会关闭流吗?

Nef*_*zen 159 c# stream streamreader

我正在向要写入的方法发送一个流,在这些方法中我使用的是二进制阅读器/ wrtier.当读取器/写入器被处理时,using或者仅在未被引用时,流也被关闭?

我会发送一个BinaryReader/Writer,但我也在使用StreamReader(也许我应该绕过它.我只使用GetLine和ReadLine).如果每次作家/读者关闭时关闭流,这是非常麻烦的.

Jon*_*eet 198

是的,StreamReader,StreamWriter,BinaryReaderBinaryWriter所有关闭/处置其底层流时,你叫Dispose他们.如果读者/作者只是垃圾收集,他们处理流 - 你应该总是处理读者/作者,最好是using声明.(事实上​​,这些类都没有终结器,也没有.)

就个人而言,我更喜欢使用流的using语句.你可以using非常巧妙地嵌套没有大括号的语句:

using (Stream stream = ...)
using (StreamReader reader = new StreamReader(stream, Encoding.Whatever))
{
}
Run Code Online (Sandbox Code Playgroud)

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

  • @HB:在这种情况下忽略它是安全的.或者您可以在构造函数调用"StreamReader"中创建流.鉴于`IDisposable.Dispose`的文档显式声明:"如果对象的Dispose方法被多次调用,该对象必须忽略第一个之后的所有调用.该对象不能抛出异常,警告看起来很虚伪.如果它的Dispose方法被多次调用." (13认同)
  • 这种嵌套导致VS代码分析器抱怨:`CA2202:Microsoft.Usage:对象'stream'可以在方法'...'中多次处理.为了避免生成System.ObjectDisposedException,您不应该在对象上多次调用Dispose.这应该被忽略吗?到目前为止我没有得到任何例外...... (10认同)
  • @JonSkeet:实际上有一个[这个页面](http://msdn.microsoft.com/en-us/library/ms182334.aspx),你是对的,这是假的:) (5认同)
  • 哦,好的,只有在调用Dispose时才会发生,而不是在最终确定时. (2认同)

aca*_*lon 42

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

public StreamReader( Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize, bool leaveOpen )
Run Code Online (Sandbox Code Playgroud)

唯一的问题是,为其他参数设置的内容并不完全明显.这是一些帮助:

从StreamReader构造函数(Stream)的msdn页面:

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

这只是叶detectEncodingFromByteOrderMarks其判断的源代码true

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

public StreamReader(Stream stream, bool detectEncodingFromByteOrderMarks)
        : this(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks, DefaultBufferSize) {
}
Run Code Online (Sandbox Code Playgroud)

如果暴露了一些默认值或者参数是可选的,那么我们就可以指定我们想要的那些默认值.

  • 对于像我这样的懒人,保持流开放的简短答案就像:`using(var streamReader = new StreamReader(myStream,Encoding.UTF8,true,1024,true))` (2认同)
  • 您可以使用命名参数来指定所需的参数,并保留其余参数的默认值:`using (var streamReader = new StreamReader(myStream, LeaveOpen: true))` (2认同)

Bri*_*sen 29

是的,它确实.您可以通过使用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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


Sun*_*est 13

迟了六年但也许这可能对某人有所帮助.

StreamReader在处理时会关闭连接.但是,"使用(Stream stream = ...){...}"与StreamReader/StreamWriter会导致Stream被处理两次:(1)当StreamReader对象被丢弃时(2)和当Stream使用块时关闭.运行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
{
    if(stream != null)
        stream.Dispose();
}
Run Code Online (Sandbox Code Playgroud)

代替...

// Generates a CA2202 warning
using (Stream stream = new FileStream("file.txt", FileMode.Open))
using (XmlReader reader = new XmlReader (stream))
{
    // Use the reader object...
}
Run Code Online (Sandbox Code Playgroud)

  • 是的,这对我来说非常有用,现在7年后:) (2认同)
  • 该警告也在已接受答案的评论中进行了讨论。Jon Skeet 在那里提供了一些建议。 (2认同)