How to Close a Streamwriter Without Closing Its Basestream

Is there any way to close a StreamWriter without closing its BaseStream?

If you are using .NET Framework 4.5 or later, there is a StreamWriter overload using which you can ask the base stream to be left open when the writer is closed.

In earlier versions of .NET Framework prior to 4.5, StreamWriter assumes it owns the stream. Options:

  • Don't dispose the StreamWriter; just flush it.
  • Create a stream wrapper which ignores calls to Close/Dispose but proxies everything else along. I have an implementation of that in MiscUtil, if you want to grab it from there.

Does .Disposing a StreamWriter close the underlying stream?

StreamWriter.Close() just calls StreamWriter.Dispose() under the bonnet, so they do exactly the same thing.
StreamWriter.Dispose() does close the underlying stream.

Reflector is your friend for questions like this :)

Is it possible to make StreamWriter overwrite line without closing the .txt?

Similar to the answer here you want to reset the file stream each time you write

public void OverwriteFile(Stream writer, string text) 
{
writer.BaseStream.Seek(0,0);
writer.BaseStream.SetLength(Encoding.UTF8.GetBytes(text).Length));
writer.Write(text);
writer.Flush();
}

Dispose the stream once you are finished writing to it.

Does disposing streamreader close the stream?

Yes, StreamReader, StreamWriter, BinaryReader and BinaryWriter all close/dispose their underlying streams when you call Dispose on them. They don't dispose of the stream if the reader/writer is just garbage collected though - you should always dispose of the reader/writer, preferrably with a using statement. (In fact, none of these classes have finalizers, nor should they have.)

Personally I prefer to have a using statement for the stream as well. You can nest using statements without braces quite neatly:

using (Stream stream = ...)
using (StreamReader reader = new StreamReader(stream, Encoding.Whatever))
{
}

Even though the using statement for the stream is somewhat redundant (unless the StreamReader constructor throws an exception) I consider it best practice as then if you get rid of the StreamReader and just use the stream directly at a later date, you'll already have the right disposal semantics.

StreamWriter can't be closed while its wrapped Pipe isn't drained?

So the problem is down to the way Windows Named Pipes work. When CreateNamedPipe is called you can specify the output buffer size. Now the documentation says something like this:

The input and output buffer sizes are advisory. The actual buffer size reserved for each end of the named pipe is either the system default, the system minimum or maximum, or the specified size rounded up to the next allocation boundary.

The trouble here is the NamedPipeServerStream constructor passes 0 as the default output size (we can verify this using the source, or in my case just firing up ILSpy). You might assume this would create a "default" buffer size, as per the comment, but it doesn't, it literally creates a 0 byte output buffer. This means that unless someone is reading the buffer then any write to the pipe blocks. You can also verify the size using the OutBufferSize property.

The behaviour you're seeing is because when you dispose the StreamWriter it calls Write on the pipe stream (as it has buffered the contents). The write call blocks, so Dispose never returns.

To verify this we'll use WinDBG (as VS just shows the blocking thread on the sw.Dispose call).

Run the server application under WinDBG. When it's blocking pause the debugger (hit CTRL+Break for example) and issue the following commands:

Load the SOS debugger module: .loadby sos clr

Dump all running stacks with interleaved managed and un-managed stack frames (might need to run this twice because of a dumb bug in sos.dll): !eestack

You should see the first stack in the process looks something this (heavily edited for brevity):

Thread   0
Current frame: ntdll!NtWriteFile+0x14
KERNELBASE!WriteFile+0x76, calling ntdll!NtWriteFile
System.IO.Pipes.PipeStream.WriteCore
System.IO.StreamWriter.Flush(Boolean, Boolean))
System.IO.StreamWriter.Dispose(Boolean))

So we can see that we're stuck in NtWriteFile which is because it can't write out the string to a buffer of size 0.

To fix this issue is easy, specify an explicit output buffer size using the one of the NamedPipeServerStream constructors, such as this one. For example this will do everything the default constructor will do but with a sensible output buffer size:

new NamedPipeServerStream("testpipe", PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.None, 0, 4096)

Using statement around XmlWriter causes premature closing of stream

Look at the stacktrace: the exception is happening when XmlWriter is disposed, at the end of its block. It is disposed, it flushes, it tries to write to the underlying stream and bang! - something has already disposed the underlying stream.

StreamReader's block ends just before XmlWriter's block, and this disposal also (by default) disposes the underlying stream. It's the only thing that could have done it.

The reason for it working in the other cases is that StreamWriter must not flush on dispose (or much more likely - it doesn't need to flush because its buffer is either empty or non-existing). This means that it doesn't matter that StreamReader has nipped in before it.

In the last case it works because XmlWriter isn't being disposed, and isn't trying to flush at all (but then, it evidently doesn't need to anyway, as you've already manually flushed, and the output is correct - I wonder why its dispose method insists on flushing then? but it is doing)

The general solution here is to use using more selectively. You can either miss it out completely for StreamReader, or you can pass the 'leaveOpen' parameter to it.

My usual approach is to only worry about disposing the stream, as it's always the stream that is linked to an unmanaged resource needing disposal. The disposing of readers and writers is really just a nice means of succinctly disposing the stream.

Avoiding dispose of underlying stream

If you subclass the MemoryStream, this will work but you have to call ManualDispose method to close the underlying stream.

I´m not sure but I think this object will be garbage-collected when it goes out of scope.

public sealed class ManualMemoryStream : MemoryStream
{
protected override void Dispose(bool disposing)
{
}
public void ManualDispose()
{
base.Dispose(true);
}
}

Edit:

This is an alternative if you want the MemoryStream to be flushed and ready to be read from top.

public sealed class ManualMemoryStream : MemoryStream
{
protected override void Dispose(bool disposing)
{
Flush();
Seek(0, SeekOrigin.Begin);
}
public void ManualDispose()
{
base.Dispose(true);
}
}


Related Topics



Leave a reply



Submit