views:

479

answers:

4

Hey guys I recently came across this web page http://www.yoda.arachsys.com/csharp/readbinary.html explaining what precautions to take when reading from a filestream. The gist of it is that the following code doesnt always work:

// Bad code! Do not use!
FileStream fs = File.OpenRead(filename);
byte[] data = new byte[fs.Length];
fs.Read (data, 0, data.Length);

This is dangerous as the third argument for Read is a maximum of bytes to be read, and you should use Read's return value to check how much actually got read.

My question is should you take the same precautions when reading from a memorystream and under which circumstances might Read return before all bytes are read?

Thanks, Bas

+5  A: 

Well, I believe the current implementation of MemoryStream will always fill the buffer if it can - unless you've got some evil class derived from it. It's not guaranteed though, as far as I can see. The documentation even contains the warning:

An implementation is free to return fewer bytes than requested even if the end of the stream has not been reached.

Personally, I'd always code this defensively unless it makes things much easier. You never know when someone will change the type of stream and not notice what's happened.

Normally with a MemoryStream though, I want all the bytes at once: so I call MemoryStream.ToArray. This is guaranteed to work, and if someone changes the code to not use a MemoryStream, it will fail to compile as that member's only on MemoryStream. For general streams, I use a utility method which reads fully from a stream and returns a byte array.

Jon Skeet
thanks, I didnt notice MemoryStream.ToArray
Bas Smit
What gotcha's is there with writing to a file. Is there also as many checks that you need to do, to ensure that the whole file gets created? I am working with 10mb XML files, the code has worked okay up to now, but that was mainly working with 20k image files.
Rihan Meij
@Rihan: Other than making sure you close your stream at the end (which automatically flushes it) you should be fine. Calls to `Write` should block until *all* the data is written (but not necessarily flushed).
Jon Skeet
A: 

Yes, you should always be aware of how many bytes were actually read from a stream when calling Read. The roout cause can vary depending on the stream type, but essentially the return value will be less than the actual buffer size whenever you are trying to read beyond the end of the stream.

Noldorin
+1  A: 

I cant think of any reason for a normal MemoryStream. Unmanaged might be a different story.

Anyways, the GetBuffer() ToArray() command is always handy. :)

leppie
A: 

Here's what MSDN says about it:

...can be less than the number of bytes requested if that number of bytes are not currently available, or zero if the end of the stream is reached before any bytes are read.

and

An implementation is free to return fewer bytes than requested even if the end of the stream has not been reached.

Note the term "an implementation...".

M4N