简体   繁体   中英

Will closing a FileStream close the StreamReader?

If I use a FileStream to create a StreamReader, will the StreamReader close when I close the FileStream or will I need to close the StreamReader too?

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

Essentially yes. You don't actually have to close a StreamReader. If you do, all it does is closes the underlying stream.

@Bruno makes a good point about closing the outer-most wrapper. It is good practice to close the outer-most stream and let it close underlying streams in order to ensure all resources are released properly.

From Reflector...

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

No. You should close the reader instead. In practice, this might not present any problem but, the StreamReader could add some overhead that might need to be cleaned. So you should always close the top most wrapper.

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

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

You don't need to close the StreamReader because it doesn't own any unmanaged resources. Closing the FileStream is sufficient. You can rewrite your code with using like this:

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

In general if you are in doubt it is best to be safe and Dispose all IDisposable objects when you have finished using them.

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

不。最好的办法是按照打开它们的相反顺序关闭它们。

It seems to me that the best way to do this overall would be to have the FileStream closing only itself. It does not implicitly have knowledge of anything that exists in a layer above itself, so it is effectively an error for it to do anything that would affect those higher layers.

Having said that, the higher-level constructs should not axiomatically assume anything about any supplied underlying layer as well, or if they do so, they should do so explicitly:

1) If it was created from an existing stream, then the higher-level construct should be able to be closed INDEPENDENTLY of the underlying stream (effectively just disposing of any resources it allocated for its own use), or closed INCLUDING the underlying stream. These should be two distinct function calls, for example Close() and CloseSelf() (if this were to be implemented in such a way as to be backward compatible with existing code).

2) If it was not created from an existing stream (that is, the constructor had to create the underlying stream), then closing the higher-level construct should force the underlying stream to close as well, since in that case the underlying stream is an implicit part of the higher-level construct. In this case, CloseSelf() would simply call Close().

It seems wasteful to implement these classes the way it was done. If you plan to use the same file for (as an example) serial input and serial output, you are effectively forced by the system to treat it as two distinct entities if you wish to gain access to the higher level functionality of the descendant classes. Your alternative is to stick to the lower level construct and implement the higher-level functionality yourself - effectively re-implementing your own special versions of descendant classes that already exist.

If it were done as described above, the typical functionality would be as simple to implement as it is now, but for more sophisticated applications one would retain the ability to place a single lock on a file and re-purpose it as required when required as opposed to having to relinquish the lock and all associated resources and then instantly reallocate them all over again - adding overhead and memory fragmentation to the system without any valid reason.

Under the existing conditions, though, the correct thing is clear. The FileStream cannot be assumed to know anything about any object it becomes a part of, so you must close the outermost enclosing construct. This applies regardless of whether or not it works either way, as Bruno et al have noted, and for the reason they gave - compatibility. Assumption is the great-granddaddy of the ugliest bugs.

An interesting aside is that closing a StreamReader or writer will affect the read/write status of the owning FileStream. This seems to mean that you cannot use a StreamReader and then a StreamWriter using the same filestream.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM