Read Write from MemoryStream

I use a DataContractJsonSerializer which I like to output to Stream. I want the top and bottom outputs of the serializer, so I used StreamWriter to write alternately to the extra bits that I need.

 var ser = new DataContractJsonSerializer(typeof (TValue)); using (var stream = new MemoryStream()) { using (var sw = new StreamWriter(stream)) { sw.Write("{"); foreach (var kvp in keysAndValues) { sw.Write("'{0}':", kvp.Key); ser.WriteObject(stream, kvp.Value); } sw.Write("}"); } using (var streamReader = new StreamReader(stream)) { return streamReader.ReadToEnd(); } } 

When I do this, I get an ArgumentException "The stream is not readable."

I probably ruined everything, so all answers are welcome. Thank.

+43
c #
Aug 05 '09 at 10:43
source share
4 answers

Three things:

  • Do not close StreamWriter . This will close the MemoryStream . However, you need to clear the writer.
  • Reset the position of the stream before reading.
  • If you are going to write directly to the stream, you first need to clear the record first.

So:

 using (var stream = new MemoryStream()) { var sw = new StreamWriter(stream); sw.Write("{"); foreach (var kvp in keysAndValues) { sw.Write("'{0}':", kvp.Key); sw.Flush(); ser.WriteObject(stream, kvp.Value); } sw.Write("}"); sw.Flush(); stream.Position = 0; using (var streamReader = new StreamReader(stream)) { return streamReader.ReadToEnd(); } } 

There is another simple alternative. Everything you do with a stream when reading converts it to a string. You can make it easier:

 return Encoding.UTF8.GetString(stream.GetBuffer(), 0, (int) stream.Length); 

Unfortunately, MemoryStream.Length will throw if the stream has been closed, so you probably want to call the StreamWriter constructor, which does not close the underlying stream, or simply not close the StreamWriter .

I am worried that you are writing directly to the stream - what is ser ? Is this an XML serializer or binary? If it is binary, your model is somewhat erroneous - you should not mix binary and text data without worrying about it. If this is XML, you may find that at the end of the line you end up marking the byte order, which can be problematic.

+85
Aug 05 '09 at 10:55
source share

setting the position of memory streams to the beginning can help.

  stream.Position = 0; 

But the main problem is that StreamWriter closes your memory stream when it is closed.

Just clearing this thread when you finish using the block for it, and only getting rid of it, you read the data from the memory stream, will solve it for you.

You may also consider using StringWriter instead of ...

 using (var writer = new StringWriter()) { using (var sw = new StreamWriter(stream)) { sw.Write("{"); foreach (var kvp in keysAndValues) { sw.Write("'{0}':", kvp.Key); ser.WriteObject(writer, kvp.Value); } sw.Write("}"); } return writer.ToString(); } 

This requires that your WriteObject call for serialization can accept a TextWriter instead of a Stream.

+6
Aug 05 '09 at 10:46
source share

To access the contents of a MemoryStream file after it is closed , use the ToArray() or GetBuffer() methods. The following code demonstrates how to get the contents of a memory buffer as a UTF8 encoded string.

 byte[] buff = stream.ToArray(); return Encoding.UTF8.GetString(buff,0,buff.Length); 

Note. ToArray() easier to use than GetBuffer() , because ToArray() returns the exact length of the stream, not the size of the buffer (which may be larger than the contents of the stream). ToArray() makes a copy of the bytes.

Note: GetBuffer() more advanced than ToArray() since it does not make a copy of bytes. You need to take care of the possible undefined bytes at the end of the buffer by counting the length of the stream, not the size of the buffer. Using GetBuffer() highly recommended if the stream size is more than 80,000 bytes, because a copy of ToArray will be allocated in a bunch of large objects, where its life time can become problematic.

It is also possible to clone the original MemoryStream as follows in order to facilitate access to it via StreamReader, for example.

 using (MemoryStream readStream = new MemoryStream(stream.ToArray())) { ... } 

The ideal solution is to access the original MemoryStream until it is closed, if possible.

+3
Jun 17 '15 at 15:21
source share

Just a wild hunch: maybe you need to reset the stream block? Perhaps the system sees that there are pending entries. With a flush, you know for sure that the stream contains all the written characters and is readable.

+1
Aug 05 '09 at 10:46
source share



All Articles