views:

11383

answers:

8

If I am given a MemoryStream that I know has been populated with a String, how do I get a String back out?

+8  A: 

use a StreamReader, then you can use the ReadToEnd method that returns a string.

Darren Kopp
+19  A: 

Using a StreamReader to convert the MemoryStream to a String.

<Extension()> _
Public Function ReadAll(ByVal memStream As MemoryStream) As String
    ' Reset the stream otherwise you will just get an empty string.
    ' Remember the position so we can restore it later.
    Dim pos = memStream.Position
    memStream.Position = 0

    Dim reader As New StreamReader(memStream)
    Dim str = reader.ReadToEnd()

    ' Reset the position so that subsequent writes are correct.
    memStream.Position = pos

    Return str
End Function
Brian
Setting the Position to 0 limits the reuse ability of the method -- it is best to let the caller manage this. What if the stream contains data prior to the string, that the caller knows how to handle?
Alex Lyman
The using statement will ensure that your StreamReader gets disposed, but the documentation says that StreamReader closes the underlying stream when it gets disposed. Therefore, your method closes the MemoryStream it gets passed, which is conceptually uncool for callers even if I doubt MemoryStream.Dispose does much.
Trillian
You are correct. It is typically a bad idea to use the Dispose method on the stream helper classes, especially if the stream is passed into a method as a parameter. I'll update this answer. I also have a more complete answer below.
Brian
A: 

Never quite sure if reader.close is always required. I have had issues in the past so as a rule I always do just to be on the safe side.

Crusty
If you enclose the Reader in a "using" block the IDisposable is magically taken care of and Close is called.
Scott Saad
+1  A: 

I would just argue your setting Position to 0 because it unnecessarily limits the function use. It states that you always want to read the string from the beginning of the stream.

EDIT: answering Alex Lyman I believe my reputation doesn't allow me to comment on answers (either that or I'm blind).

Leonardo Constantino
Responding to an answer with another answer is frowned upon, better to use the "add comment" button found at the bottom of the answer.
Alex Lyman
A: 

While the first comment's code nearly gets it right, it still not quite there. The return statement will prevent the reader's dispose method from being called.

So the proper method of doing this is: Public Function GetString(ByVal memStream As MemoryStream) As String Dim tReturn as String = String.Empty ' Important to reset the stream otherwise you will just get an empty string. memStream.Position = 0 Using reader As New StreamReader(memStream) tReturn = reader.ReadToEnd() End Using Return tReturn End Function

From http://msdn.microsoft.com/en-us/library/htd05whh.aspx:"the Using block guarantees disposal of the resources, no matter how you exit the block."
Brian
+8  A: 

This sample shows how to read and write a string to a MemoryStream.


static void Main(string[] args)
{
    using (var ms = new MemoryStream())
    {
        var sw = new StreamWriter(ms);
        sw.WriteLine("Hello World");
        // The string is currently stored in the 
        // StreamWriters buffer. Flushing the stream will 
        // force the string into the MemoryStream.
        sw.Flush();

        // If we dispose the StreamWriter now, it will close 
        // the BaseStream (which is our MemoryStream) which 
        // will prevent us from reading from our MemoryStream
        //DON'T DO THIS - sw.Dispose();

        // The StreamReader will read from the current 
        // position of the MemoryStream which is currently 
        // set at the end of the string we just wrote to it. 
        // We need to set the position to 0 in order to read 
        // from the beginning.
        ms.Position = 0;
        var sr = new StreamReader(ms);
        var myStr = sr.ReadToEnd();
        Console.WriteLine(myStr);
    }

    Console.WriteLine("Press any key to continue.");
    Console.ReadKey();
}
Brian
Isn't it going to dispose of the StreamWriter when the function goes out of scope anyway?
Tim Keating
Dispose is not called when a variable goes out of scope. Finalize will be called when the GC gets around to it, but Dispose is something that must be called before the variable goes out of scope. I don't call it above because I know the implementation of StreamWriter and StreamReader don't require Dispose to be called, it just passes the call to the underlying stream. However, a legitimate argument can be made for calling Dipose for anything that implements IDisposable since you can't guarantee a future release won't require it to be disposed.
Brian
+1  A: 

You can also use

ASCIIEncoding.ASCII.GetString(ms.ToArray());

I don't think this is less efficient, but I couldn't swear to it. It also lets you choose a different encoding, whereas using a StreamReader you'd have to specify that as a parameter.

Coderer
A: 

a slightly modified version of the first answer allows optional management of read start, this seems to be the easiest method. probably not the most efficient, but easy to understand and use.

Public Function ReadAll(ByVal memStream As MemoryStream, Optional ByVal startPos As Integer = 0) As String
    ' reset the stream or we'll get an empty string returned
    ' remember the position so we can restore it later
    Dim Pos = memStream.Position
    memStream.Position = startPos

    Dim reader As New StreamReader(memStream)
    Dim str = reader.ReadToEnd()

    ' reset the position so that subsequent writes are correct
    memStream.Position = Pos

    Return str
End Function
James