Re: I/O buffering

Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance



On Thu, 05 Feb 2009 13:11:04 -0800, <beginwithl@xxxxxxxxx> wrote:

a) I didn’t mean to imply that FileStream is special class for
buffering, but since FileStream, StreamWriter and StreamReader all
have buffering capabilities, why does Net also have special buffering
classes ( those with word Buffer in their name )?

Without a specific example, it's impossible to say. But, as an example: there's a BufferedStream class. As I mentioned, not all Stream classes buffer. But, sometimes it's useful to add buffering to a non-buffering Stream class. Using BufferedStream is a way to do that.

One would not normally use BufferedStream with a FileStream, since that would be pointless. But you might, for example, use it with a NetworkStream, or some other Stream implementation that doesn't itself offer buffering functionality. Note, of course, in some sense there's pretty much no such thing as an i/o class that doesn't do buffering. Even with NetworkStream, which doesn't internally do buffering, there are buffers _somewhere_.

b) In any case, based on what criteria does FileStream object chooses
whether it should write data directly to a file or buffer it instead
( so far it always seemed to write it directly to a file )?

It always buffers. I was incorrect previously in stating that you could specify a buffer size of 0. That's an illegal value for the buffer size for FileStream.

Ah, so StreamWriter.Flush does also flush the underlying stream
buffers

Yes. I think the docs are bit weak in this area, but flushing the StreamWriter also flushes the underlying stream.

But data also gets automatically flushed when FileStream’s buffer is
full?!

Of course. Otherwise how would the buffer be made empty so that new data could be added?

Now, if you _do_ call Flush(), there is in fact a possibility that the
buffers from the OS object on (i.e. out of FileStream's control) wouldn't
be written immediately and would be written at some later time, even after
your application has stopped.

What are the chances of that happening ( small, I hope )?

The chances of the delay in writing to the physical media are quite good, actually. But, the delay is in practice fairly short and only a complete system failure (e.g. lose power) before the data is finally written would produce any observable consequences.

So, don't pull the plug on your PC at the same time your program is flushing data.

Why would having two wrapper classes be considered a bad idea
( besides the problems with Close() )?

Because that's the nature of wrappers. Once you've wrapped an instance of something in another class, that other class owns that instance. If you then try to wrap it in yet another instance of a class, then you are basically saying your wrapped object has two owners.

In certain cases, of course, multiple ownership is valid. But it has to be prearranged explicitly, and supported by the classes involved. Otherwise, single ownership is the assumed standard.

There are specific reasons this is especially important in the case of StreamWriter and StreamReader, but really these just follow the more general rule. Those specific reasons are just examples of why the rule exists.

At best, you can call Flush() on both StreamWriter's, and then close them
(catching and ignoring the exception on the second one you close).

But does calling Close() on sw1 has any effect at all, since exception
being thrown suggests that sw1.Close() failed at whatever it was
trying to do?!

Very little effect. The primary purpose of Close() is to close the underlying stream.

> We could, instead of
> closing ‘fs’ directly, close one of its wrapper classes, say ‘sw’. But
> we’d still need to somehow close ‘sw1’?!

Yes, you should (though in reality, probably not much harm would come from
failing to).

* By “Yes, you should” were you referring to closing 'sw' or 'sw1' or
both?

As an answer to a question, it applies to the question.

* Thus,were you implying that there would be no harm if I failed to
close either of the two?

I implied no such thing. I _stated_ that "not much harm would come". "Not much harm" is not the same as "no harm".

* Why would there be no harm? Due to the fact that by closing
underlying stream we already released the file resources?

Two reasons: first, yes...if you've closed the stream, you've already accomplished the main thing that closing the writer(s) would accomplish. Second, you have very good chances (but no guarantees) that the finalizer will be executed and perform the work your explicit call to Close() would have done.

These are not reasons to ignore the advice to do things correctly. I'm just saying that of the sins you might commit, this is down on the more benign end of the scale.

In reality, the answer is "don't do that". It's an ugly way
to use StreamWriter. If you really must attach two StreamWriter's to the
same FileStream, you should create an intermediary Stream sub-class that
itself wraps FileStream, and which is used to create each StreamWriter,
and which ignores the close/dispose from the StreamWriters (you would of
course have to close the FileStream explicitly yourself, _after_ the
StreamWriter's have been closed).

* So this subclass would only call FileStream when both of
StreamWriters called Close/Dispose ( when first StreamWriter would
call Close(), it would ignore it, but when second also would call it,
then it would close the underlying stream? )?

No. It would always ignore a Close(). Your own code would have to explicitly dispose your custom Stream class, when you were sure you were done with it.

* But how would this Stream sub-class prevent StreamWriters from
calling Close() directly on underlying FileStream?

How would StreamWriters know about the underlying FileStream? Where would they get that reference?

This is a bit off topic:

From MSDN:
“Be sure to call the Dispose method on all FileStream objects”

A quote out of context is almost never very useful for discussion.

That said, some points:

-- If an object implements IDisposable, you should always call Dispose() when you're done.
-- You don't necessarily call Dispose() explicitly. There are ways that Dispose() can be called implicitly, and this meets the requirements of a statement like what you've quoted.
-- For the stream-related classes, Close() and Dispose() are basically equivalent. Stream even specifically documents this. The only thing Close() is supposed to do is call Dispose().

a) Why? Don’t you also clean up the resources or at least release the
file handle by simply calling FileStream.Close()?

See above.

b) So you should always call FileStream.Dispose() instead of
FileStream.Close()? Book hasn’t mention anything like tha and in fact
always used Close() instead. Uh!

You can use either or both. I personally go back and forth; conceptually, I feel that one should do both. But on the other hand, MSDN is pretty clear about the equivalence of the two, and Dispose() is generally a lot more convenient to call correctly, due to the "using" statement.

c) I haven’t bothered learning Dispose() simply due to the fact that
may book claims one only needs it when dealing with unmanaged
resources. But since you should always call Dispose() on FileStream
object, I assume FileStream handles unmanaged resources and as such it
needs to call Dispose() to release file handles and locks as soon as
possible?

Sure. It doesn't really matter why an object implements IDisposable. If it does, you need to call Dispose() on it when you're done with it.

d) But then, don’t most .Net classes call Win32 API functions? Thus,
shouldn’t you then call Dispose() on most of Net objects?

Calling a Win32 function isn't what creates the need for disposal. It's the use of data structures that can't be tracked using the managed memory management. I.e. "unmanaged resources".

Regardless, the rule is simple: you should be calling Dispose() on any object that implements IDisposable. And of course, you can't call Dispose() on any other object.

e)

* StreamWriter also has a Dispose() method. But since it is just a
wrapper class, I’d assume it doesn’t deal with unmanaged resources, so
why need to call it? Perhaps it calls the Dispose() of the underlying
Stream object?

It calls Close() on the underlying Stream object. Which as you know now is the same as calling Dispose().

* Thus, I should also always call StreamWriter.Dispose() instead of
StreamWriter.Close()?

Either is fine.

At least in cases where I haven’t called FileStream.Dispose()
directly?

Once your FileStream instance has been wrapped in a StreamWriter, you should not do anything else with it. StreamWriter owns it, and you need to operate on StreamWriter instead.

As with any rule, there are always exceptions to the rule. But it's a good rule, nonetheless.

BTW - I assume ‘StreamWriter buffering data’ means that when it reads
from a file, it reads more characters than requested by Read() and
thus it doesn’t have to make so many calls to the underlying system?!

Again, quotes out of context are not very useful for discussion.

Pete
.



Relevant Pages

  • Re: Best practice for streaming fairly large files from server to
    ... It looks like buffering the filestream in chunks is going to be the best ... FileStream and buffer them to the Response. ... An entire file is loaded into a memory stream then that memory stream uses ...
    (microsoft.public.dotnet.framework.aspnet)
  • Re: Segmentation fault
    ... Here I have made room for 256 characters. ... You see, printfis outputting its string to the stdout stream, ... buffering for its streams: no buffering, line buffering, and full ... not be opened explicitly -- standard input (for reading ...
    (comp.lang.c)
  • Re: I/O buffering
    ... classes (those with word Buffer in their name)? ... Stream class. ... One would not normally use BufferedStream with a FileStream, ... explicitly dispose your custom Stream class, when you were sure you were   ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Best practice for streaming fairly large files from server to
    ... It looks like buffering the filestream in chunks is going to be the best ... FileStream and buffer them to the Response. ... An entire file is loaded into a memory stream then that memory stream ...
    (microsoft.public.dotnet.framework.aspnet)
  • RE: m3u Buffering non-stop
    ... at home I have a local LAN setup that uses DHCP to automatically ... at your home to see what your actual up and down stream rates are. ... every time I try to connect, WMP just keeps Buffering over and over and I ...
    (microsoft.public.windowsmedia.player)