为什么要部署StreamReader会使流不可读?

Ars*_*nko 10 c# idisposable stream streamreader

我需要从开始到结束两次读取一个流.

但是以下代码抛出ObjectDisposedException: Cannot access a closed file异常.

string fileToReadPath = @"<path here>";
using (FileStream fs = new FileStream(fileToReadPath, FileMode.Open))
{
    using (StreamReader reader = new StreamReader(fs))
    {
        string text = reader.ReadToEnd();
        Console.WriteLine(text);
    }

    fs.Seek(0, SeekOrigin.Begin); // ObjectDisposedException thrown.

    using (StreamReader reader = new StreamReader(fs))
    {
        string text = reader.ReadToEnd();
        Console.WriteLine(text);
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么会这样?什么是真的处置?为什么操纵StreamReader会以这种方式影响相关的流?期望可以多次读取可搜索流是不合逻辑的,包括几个StreamReaders?

Han*_*ant 16

发生这种情况是因为StreamReader接管了流的"所有权".换句话说,它使自己负责关闭源流.一旦您的程序调用DisposeClose(using在您的情况下保留语句范围),它也将处置源流.打电话给fs.Dispose()你的情况.因此离开第一个using块后文件流已经死了.这是一致的行为,.NET中包含另一个流的所有流类都以这种方式运行.

有一个构造函数StreamReader允许说它拥有源流.但是,无法从.NET程序访问它,构造函数是内部的.

在这种特殊情况下,您可以通过不使用using-statement来解决问题StreamReader.然而,这是一个相当毛茸茸的实现细节.肯定有更好的解决方案可供您使用,但代码太合成了,无法提出真正的解决方案.


Kir*_*oll 7

目的Dispose()是在完成流后清理资源.读者影响的原因是因为读者只是过滤流,因此除了在链接对源流的调用的上下文中之外,处理读取器没有任何意义.

要修复代码,请在整个时间内使用一个阅读器:

using (FileStream fs = new FileStream(fileToReadPath, FileMode.Open))
using (StreamReader reader = new StreamReader(fs))
{
    string text = reader.ReadToEnd();
    Console.WriteLine(text);

    fs.Seek(0, SeekOrigin.Begin); // ObjectDisposedException not thrown now

    text = reader.ReadToEnd();
    Console.WriteLine(text);
}
Run Code Online (Sandbox Code Playgroud)

编辑以解决以下评论:

在大多数情况下,您不需要像在代码中那样访问基础流(fs.Seek).在这些情况下,StreamReader链接其对底层流的调用这一事实允许您通过不使用usings流的语句来节省代码.例如,代码看起来像:

using (StreamReader reader = new StreamReader(new FileStream(fileToReadPath, FileMode.Open)))
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

  • @ MainMa,Dispose()的目的是始终确保与给定IDisposable相关联的所有资源都被清除。由于阅读器和流表示相同的实体,因此配置一个实体与配置另一个实体具有相同的效果。 (2认同)