Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it okay to not close StreamReader/StreamWriter to keep the underlying stream open?

Tags:

c#

stream

I have a class that essentially wraps a Stream for reading/writing, but that stream is expected to be managed by the consumer of that class. For ease of use, I use StreamReader and StreamWriter classes to perform I/O operations on the stream. Normally I'd wrap the reader and writer in using blocks, but I want to avoid closing the reader and writer because doing so also closes the underlying stream and I have to keep it open.

Is it safe in terms of memory/resource management to not close a StreamReader/StreamWriter if I expect the underlying Stream to be managed by the caller? Will the reader and writer be garbage collected when the stream is explicitly closed elsewhere?

public class Wrapper 
{
    private Stream _underlyingStream;
    public Wrapper(Stream underlyingStream) 
    {
        _underlyingStream = underlyingStream;
    }

    public string GetValue() 
    {
        _underlyingStream.Seek(0, SeekOrigin.Begin);
        var reader = new StreamReader(_underlyingStream);
        return reader.ReadToEnd(); // we're done, but the stream is not ours to close
    }
}
like image 235
Adam Lear Avatar asked Dec 16 '10 22:12

Adam Lear


People also ask

Do I need to close StreamReader?

1 Answer. No, there is no need to explicitly call reader. Close if the reading process is inside a using block. By using a using statement (that sounds awkward out loud) everything will be closed and disposed when the code exits the block.

Does closing a StreamReader close the underlying stream?

Yes, StreamReader , StreamWriter , BinaryReader and BinaryWriter all close/dispose their underlying streams when you call Dispose on them.

Does StreamWriter dispose underlying stream?

It does not dispose the stream. It simply closes it.


2 Answers

If nobody closes the streams then ultimately the finalizer will be called which should call dispose and close them upon GC. But that's quite a crap-shoot resource-wise because it leaves whatever possibly-expensive resources allocated until GC. It could get worse the longer your object lives, especially if it survives collections to be promoted to gen 1 or even 2.

It sure would be nice if you could present something to your caller that isolates this. Perhaps you can cache something from the stream so you can close it while still serving the content to your caller?

EDIT after your edit: Now that I see your caller PASSES you a stream to operate on, my answer has to be different! It's very clear that your caller should be managing the stream's lifetime. I had the impression at first that your class created a stream and hoped the caller managed it.

like image 88
n8wrl Avatar answered Oct 07 '22 15:10

n8wrl


The easiest way to solve this is to wrap the stream in your own class that derives from System.IO.Stream

Example: http://csharptest.net/browse/src/Library/IO/NonClosingStream.cs

like image 32
csharptest.net Avatar answered Oct 07 '22 15:10

csharptest.net