我正在向要写入的方法发送流,在这些方法中,我使用的是二进制读卡器/wrtier。当读写器被using释放,或者只是当它没有被引用时,流是否也关闭了??
我会发送一个BinaryReader/Writer,但我也在使用一个StreamReader(也许我应该绕过它)。我只是把它用于getline和readline)。如果每次编写器/读卡器关闭流时都将其关闭,那么这将非常麻烦。
是的,当您调用Dispose时,StreamReader、StreamWriter、BinaryReader和BinaryWriter都会关闭/处理它们的底层流。但是,如果读写器只是垃圾收集,那么它们不会处理流-您应该始终处理读写器,最好使用using语句。(实际上,这些类都没有终结器,也不应该有终结器。)
就我个人而言,我也更喜欢流有一个using语句。您可以不使用大括号非常整齐地嵌套using语句:
1 2 3 4
| using (Stream stream = ...)
using (StreamReader reader = new StreamReader (stream, Encoding .Whatever))
{
} |
号
尽管流的using语句有点多余(除非StreamReader构造函数抛出异常),但我认为最好的做法是,如果去掉StreamReader,稍后直接使用流,就已经有了正确的处理语义。
- 哦,很好,它只在调用Dispose时发生,而不是在假定完成时发生。
- @那是因为不能保证你的物品最终会是什么顺序。如果streamreader和底层流都符合定案条件,则GC可能首先定案流,然后streamreader将没有对流的引用。因此,只能释放finalize内部的非托管资源(例如,文件流在finalize中关闭其Windows文件句柄)。哦,当然,如果您从未处理过,那么流最终仍将被收集(文件关闭)。不处理流只是一种非常糟糕的做法。
- 这种嵌套导致vs代码分析器抱怨:CA2202 : Microsoft.Usage : Object 'stream' can be disposed more than once in method '...'. To avoid generating a System.ObjectDisposedException you should not call Dispose more than one time on an object.应该忽略它吗?到目前为止我没有得到任何例外…
- @H.B.:在这种情况下忽略它是安全的。或者您可以在对StreamReader的构造函数调用中创建流。这个警告在我看来是假的,因为IDisposable.Dispose的文档显式地声明:"如果一个对象的Dispose方法被多次调用,那么该对象必须忽略第一次调用之后的所有调用。如果多次调用对象的Dispose方法,则该对象不得引发异常。"
- @jonsket:这里的问题可能是,如果一个对象被释放在多个地方,那么很难知道在哪个点可以访问该对象,因此,如果最终访问了被释放的流,则可能会发生异常。
- @H.B.:可能。如果是这样的话,措辞肯定会有所改进。
- @乔恩斯基特:事实上有一页是关于这个的,你是对的,这是假的。
- 我本来打算用你的例子,直到我读到关于"ca2202:不要多次处理对象"的最新文章stackoverflow.com/q/12000136/427684,我们应该使用微软推荐的更详细的代码,还是遵循@jhubbard80的adivce,所以stackoverflow.com/a/12011186/427684的问题。
- 进一步阅读,@jhubbard80的示例会给出不同的警告CA2000:在失去作用域之前释放对象
- @我个人也不会担心。在其他情况下,我使用using (StreamReader reader = new StreamReader(/* create stream here */, Encoding.Whatever)。我认为这只是代码分析过于挑剔:)
- 如果调用dispose(),那么这是否同样适用于数据库连接?连接是关闭还是需要先关闭?
- @Ashraf_Sada:Dispose关闭连接。
- 谢谢,对于您的确认,我想说处置关闭任何对象是真的!
- @Ashraf_Sada:当然,这取决于API——但对于"可关闭"类型来说,这是惯例。
- 这个"使用"代码能在C++中使用吗?
- @埃奇:不,这是一个C语言功能。但我相信C++由于确定性析构函数而具有类似的机制,基本上是RAI。
这是一个旧的,但我今天想做一些类似的事情,发现事情已经改变了。由于.NET 4.5,有一个leaveOpen参数:
1
| public StreamReader( Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize, bool leaveOpen ) |
唯一的问题是,为其他参数设置什么并不十分明显。以下是一些帮助:
从streamreader构造函数(stream)的msdn页:
This constructor initializes the encoding to UTF8Encoding, the
BaseStream property using the stream parameter, and the internal
buffer size to 1024 bytes.
号
只剩下detectEncodingFromByteOrderMarks,根据源代码判断,它就是true。
1 2 3 4 5 6 7
| public StreamReader(Stream stream)
: this(stream, true) {
}
public StreamReader(Stream stream, bool detectEncodingFromByteOrderMarks)
: this(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks, DefaultBufferSize) {
} |
。
如果其中一些默认值是公开的,或者参数是可选的,这样我们就可以指定所需的参数。
- 非常好的信息!从来没有听说过这个新参数,它实际上很有意义。
- 没有注意到4.5新增的内容,谢谢!
- 对于像我这样懒惰的人来说,让河流开放的简短回答是:using (var streamReader = new StreamReader(myStream, Encoding.UTF8, true, 1024, true))。
是的,的确如此。您可以通过使用Reflector查看实现来验证这一点。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| 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);
}
}
} |
已经晚了六年了,但也许这能帮上忙。
streamreader在释放连接时确实会关闭连接。但是,对streamreader/streamwriter使用(stream stream=…)…"可能会导致流被释放两次:(1)当streamreader对象被释放时(2)以及当使用流块的流关闭时。当运行vs的代码分析时,这会导致CA2202警告。
另一个直接从CA2202页面获取的解决方案是使用Try/Finally块。设置正确,这将只关闭一次连接。
靠近CA2202底部,Microsoft建议使用以下功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 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();
} |
而不是。。。
1 2 3 4 5 6
| // Generates a CA2202 warning
using (Stream stream = new FileStream ("file.txt", FileMode .Open))
using (XmlReader reader = new XmlReader (stream ))
{
// Use the reader object...
} |
。
- 是的,这对我很有用,7年后的今天:)
- 警告也在接受答案的评论中讨论。乔恩·斯基特在那里提供了一些建议。
- 另外,请注意,编译器实际上将using语句转换为try finally块。
对。对调用Dispose()和IDisposable(这是"using"所做的)应使对象清除其所有资源。这包括流刷新和关闭它们的文件描述符。
如果在您的案例中,您希望将它传递给其他方法,那么您需要确保这些方法不会在using块中进行读/写操作。
如果需要,解决此问题的一个简单方法是重写StreamWriter类的Dispose方法。有关如何操作的代码,请参阅我在此处的文章:
是否。释放streamwriter会关闭基础流?
通过"using"关键字或显式调用Dispose释放的流