处置 StreamReader 是否会关闭底层流?

问题描述 投票:0回答:7

我正在将流发送到要写入的方法,并且在这些方法中我使用二进制读取器/wrtier。当读取器/写入器被释放时,无论是通过

using
或仅当它未被引用时,流也会关闭吗??

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

c# stream streamreader
7个回答
229
投票

是的,当您对它们调用

StreamReader
时,
StreamWriter
BinaryReader
BinaryWriter
Dispose
都会关闭/处置其底层流。如果读取器/写入器只是垃圾收集,那么它们不会处置流 - 您应该始终处置读取器/写入器,最好使用
using
声明。 (事实上,这些类都没有终结器,也不应该有。)

我个人更喜欢对流使用 using 语句。您可以非常整齐地嵌套不带大括号的

using
语句:

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

即使流的

using
语句有点多余(除非
StreamReader
构造函数抛出异常),我认为这是最佳实践,因为如果你摆脱
StreamReader
并稍后直接使用流日期,你已经有了正确的处理语义。


57
投票

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

leaveOpen
参数:

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

唯一的问题是其他参数的设置并不完全明显。这里有一些帮助:

来自 msdn 页面 StreamReader 构造函数(流):

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

只剩下

detectEncodingFromByteOrderMarks
,从源代码来看是
true

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

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

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


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

17
投票

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

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

2
投票

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

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


1
投票

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

处理 StreamWriter 是否会关闭底层流?


-2
投票

通过“using”关键字或显式调用 dispose 来处置流

© www.soinside.com 2019 - 2024. All rights reserved.