【问题标题】:Will closing a FileStream close the StreamReader?关闭 FileStream 会关闭 StreamReader 吗?
【发布时间】:2010-12-20 00:23:02
【问题描述】:

如果我使用 FileStream 创建 StreamReader,当我关闭 FileStream 时 StreamReader 会关闭还是我也需要关闭 StreamReader?

public void ReadFile()
{
    var file = new FileStream("c:\file.txt", FileMode.Open, FileAccess.Read);
    var reader = new StreamReader(file);

    try
    {
        txtFile.Text = reader.ReadToEnd();
    }
    catch (Exception)
    {
        throw;
    }
    finally
    {
        file.Close();
    }
}

【问题讨论】:

标签: c# .net-3.5 filestream streamreader


【解决方案1】:

基本上是的。您实际上不必关闭 StreamReader。如果这样做,它所做的只是关闭底层流。

@Bruno 对关闭最外层的包装器提出了一个很好的观点。最好关闭最外层的流并让它关闭底层流,以确保正确释放所有资源。

从反射器...

public class StreamReader : TextReader
{
    public override void Close()
    {
        this.Dispose(true);
    }

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

【讨论】:

  • IMO,这是一个非常糟糕的做法。将来,BCL 设计人员可能会选择添加一些需要处理的额外结构......
  • @bruno conde:您自己说过应该处理最顶层的包装器。 StreamReader 是 FileReader 的顶级包装器。问题出在哪里?
  • @Kamarey,问题是 OP 只处理 FileStream。
  • @bruno conde:同意你的观点,OP 应该关闭 StreamReader。
  • @Bruno,我同意你的观点,最外面的流应该被关闭。即使它除了关闭内部流之外没有做任何有趣的事情,这也是一个好主意,这正是您所说的原因,前向兼容性。这也是一种很好的做法,这样您在处理需要关闭的其他流时就不会忘记这样做。
【解决方案2】:

没有。您应该关闭reader。实际上,这可能不会出现任何问题,但是StreamReader 可能会增加一些可能需要清理的开销。所以你应该总是关闭最顶层的包装器。

【讨论】:

    【解决方案3】:

    您也可以只使用 File.ReadAllText 方法:

    txtFile.Text = File.ReadAllText(@"c:\file.txt");
    

    【讨论】:

    • 它是如何工作的?它只是打开一个连接,读取整个文件,然后关闭文件吗?
    【解决方案4】:

    您不需要关闭 StreamReader,因为它不拥有任何非托管资源。关闭 FileStream 就足够了。您可以像这样使用using 重写您的代码:

    public void ReadFile()
    {
        using (var file = new FileStream("c:\file.txt", FileMode.Open, FileAccess.Read))
        {
            txtFile.Text = new StreamReader(file).ReadToEnd();
        }
    }
    

    一般来说,如果您有疑问,最好在使用完所有 IDisposable 对象后确保安全并处置它们。

    public void ReadFile()
    {
        using (FileStream file = new FileStream("c:\file.txt", FileMode.Open, FileAccess.Read))
        {
            using (StreamReader streamReader = new StreamReader(file))
            {
                txtFile.Text = streamReader.ReadToEnd();
            }
        }
    }
    

    【讨论】:

    • 我知道的“使用”处理对象,这是否确保连接也关闭?
    • @norlando 是的,虽然一般来说它取决于每个单独的类实现关于处置时发生的事情。在标准流的情况下,它遵循刷新缓冲区、关闭流和处理任何托管和非托管对象的逻辑步骤。
    【解决方案5】:

    没有。最好的办法是以打开它们的相反顺序关闭它们。

    【讨论】:

      【解决方案6】:

      在我看来,总体而言,最好的方法是让 FileStream 仅自行关闭。它并不隐含地知道存在于自身之上的层中的任何内容,因此它执行任何会影响那些更高层的事情实际上是错误的。

      话虽如此,更高级别的构造也不应该公理地假设任何提供的底层,或者如果他们这样做,他们应该明确地这样做:

      1) 如果它是从现有流创建的,则更高级别的构造应该能够独立关闭底层流(实际上只是处理它为自己分配的任何资源使用),或关闭 INCLUDING 底层流。这应该是两个不同的函数调用,例如 Close() 和 CloseSelf()(如果要以向后兼容现有代码的方式实现)。

      2) 如果它不是从现有流创建的(也就是说,构造函数必须创建底层流),那么关闭更高级别的构造也应该强制关闭底层流,因为在这种情况下底层流是高级构造的隐含部分。在这种情况下,CloseSelf() 会简单地调用 Close()。

      按照以前的方式实现这些类似乎很浪费。如果您计划将同一文件用于(作为示例)串行输入和串行输出,如果您希望访问后代类的更高级别功能,系统实际上会强制您将其视为两个不同的实体。您的替代方案是坚持较低级别的构造并自己实现较高级别的功能 - 有效地重新实现您自己的特殊版本的已经存在的后代类。

      如果按照上述方式完成,典型功能将像现在一样易于实现,但对于更复杂的应用程序,我们将保留在文件上放置单个锁并根据需要重新调整用途的能力当需要时,而不是必须放弃锁和所有相关资源,然后立即重新分配它们——在没有任何正当理由的情况下给系统增加开销和内存碎片。

      但是,在现有条件下,正确的事情是明确的。不能假定 FileStream 知道关于它成为一部分的任何对象的任何信息,因此您必须关闭最外层的封闭构造。正如 Bruno 等人所指出的那样,无论它是否以任何一种方式工作,这都适用,并且因为他们给出的原因 - 兼容性。假设是最丑陋的虫子的曾祖父。

      【讨论】:

        【解决方案7】:

        有趣的是,关闭 StreamReader 或 writer 会影响所属 FileStream 的读/写状态。这似乎意味着您不能使用 StreamReader 和 StreamWriter 使用相同的文件流。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-11-10
          • 1970-01-01
          • 2018-11-05
          • 1970-01-01
          • 1970-01-01
          • 2015-10-18
          • 1970-01-01
          • 2013-07-17
          相关资源
          最近更新 更多