Erwin Mayer
Erwin Mayer

Reputation: 18670

Will StreamWriter.Flush() also call FileStream.Flush()?

I have a StreamWriter which underlying stream is a FileStream. Will the following code guarantee that the FileStream also flushes its buffer into the actual file on the file system, or do I need to explicitly call Flush() on the FileStream?

using (var fs = new FileStream("blabla", FileMode.Append)) {
    using (var sw = new StreamWriter(fs)) {
        sw.WriteLine("Hello, I want to be flushed.");
        sw.Flush(); //I need this to also flush onto the file, not just to the FileStream
    }
}

As per MSDN, "Flushing the stream will not flush its underlying encoder unless you explicitly call Flush or Close", but I do not know if a FileStream can be considered an "underlying encoder".

Also, if I don't specify FileOptions.WriteThrough, am I guaranteed that the OS will eventually write the flushed line onto the disk even if the program crashes before the two streams have been closed (assuming for example no using {} blocks, only a call to Flush())?

In my scenario I need to leave the stream open (for logging) so I cannot use using {} blocks, but I would like to make sure data will always be written to the disk even if the program crashes. I can afford to lose data if there is a power shutdown and the OS has not flushed onto the disk, but otherwise I need the OS to eventually flush even if I never properly call Close() on the stream.

Upvotes: 9

Views: 4798

Answers (2)

Anirudha
Anirudha

Reputation: 32827

Streams disposal is guaranteed if used with using block!

With a chain of streams,closing the outermost stream(at the head of the chain) i.e StreamWriter in your case closes the whole lot i.e FileStream

Flush method forces internal buffer to be written immediately.Flush is automatically called when stream is closed,so you never need to do the following

s.Flush();s.Close();

So,the moment the most topmost stream is closed it flushes and then closes it underlying streams who also flush there content.

For example consider this chain

FileStream->GZipStream->StreamWriter

So,the moment you close the StreamWriter

StreamWriter flushes and closes.It also closes undelying GZipStream

GzipStream flushes and closes.It also closes underlying FileStream

FileStream flushes and closes

Upvotes: 4

Damien_The_Unbeliever
Damien_The_Unbeliever

Reputation: 239824

Yes, calling Flush on StreamWriter will cause the underlying stream to be Flushed. The 4.5 version calls a private Flush(bool,bool) function, which ends with:

if (flushStream)
{
    this.stream.Flush();
}

Where flushStream is the first parameter, this.stream is the stream that the StreamWriter was constructed on, and the call in Flush() is Flush(true,true).


(Older parts of answer - I was being very roundabout in answering. Moved most relevant part of answer to top)

It's not explicitly spelled out in the documentation anywhere I can find it, but any stream class that is constructed by passing it another stream should be assumed to "take ownership" of that stream (unless it's specifically called out otherwise).

That is, once you've constructed the StreamWriter using fs, you shouldn't perform any direct actions on fs yourself.


The part you quoted from MSDN relates to the later sentences:

This allows the encoder to keep its state (partial characters) so that it can encode the next block of characters correctly. This scenario affects UTF8 and UTF7 where certain characters can only be encoded after the encoder receives the adjacent character or characters.

That is, you may have passed data to Write such that you've given it some Unicode surrogates, but not a complete character. Flush will not write those surrogates to the stream. So long as you're always passing well formed (complete) strings to Write, you do not need to concern yourself about this.


Upvotes: 9

Related Questions