Re: I/O buffering



hi


On Feb 6, 3:30 am, "Peter Duniho" <NpOeStPe...@xxxxxxxxxxxxxxxx>
wrote:
On Thu, 05 Feb 2009 13:11:04 -0800, <beginwi...@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.


If it always buffers, then it pretty quickly gets flushed since in my
experience it always almost immediately writes it to the file. I
assume that is due to having pretty small default buffer size?!

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.

The specific reasons being ones we discussed above ( the second
StreamWriter trying to call Close() ( when the first one already
called Close ) causes an exception to be thrown ), or are there also
any other reasons ( I know it has to do with ownership )?


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.

In case of stream-related classes we implicitly call Dispose() by
calling Close()?!

     -- 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".

Uhm, I know we’ve already talked about unmanaged resources ( UR ), but
something’s still bothering me. I realize they are data structures
that aren’t under the control of GC. Anyways, my little assumption on
why not cleaning up unmanaged resources would be bad:

• URs may be in possession of something, be it a file or network
connection,
and as such other objects/apps can’t access that something
• or they represent an open door to something they “hold/are connected
to” to
uninvited guests ( such as hackers )
• and of course they cause leaking

?


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.

Sorry about that. What I meant to ask:

Since StreamReader also buffers data, I was wondering what exactly
does that mean in the case of StreamReader.
I assume 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 and the next time Read() is called, it
could perhaps simply return the result from its internal buffer
without making a call to the underlying stream?


thanx Pete
.



Relevant Pages

  • Re: FileStream.Flush not flushing?
    ... So when does the OS buffer get updated normally when using a ... FileStream? ... the file size is "correct" without closing the stream. ... >> As part of the application, I am writing information to file (that is, ...
    (microsoft.public.dotnet.framework.compactframework)
  • Re: I/O buffering
    ... StreamReader also buffers data? ... so they buffer as well. ... Neither StreamReader nor StreamWriter inherit from FileStream. ... What StreamReader and StreamWriter _do_ use is any Stream instance. ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: Assembly conversion to Pocket Pc format
    ... But in my case it is throwing exception before executing that statement what ... That is before reading buffer size it is throwing ... Stream respStream = resp.GetResponseStream; ... upload and download files in compact framework. ...
    (microsoft.public.dotnet.framework.compactframework)
  • Re: WMS source changing issue
    ... we use 5 second buffer in WMP. ... The question is - why the server is stopping broadcasting for a while (it ... clearly seen in network statistic in Task Manager) when switching to file ... We're streaming one 5Mbps live stream and one 5Mbps CBR file periodically so ...
    (microsoft.public.windowsmedia.server)
  • Re: scanf() quesion?
    ... characters are intended to ... When a stream is fully buffered, ... when a buffer is filled. ... If standard output refers to an interactive device, ...
    (comp.lang.c)

Loading