Fading Coder

An Old Coder’s Final Dance

Home > Tools > Content

Converting MemoryStream Content to and from Strings in .NET

Tools 2

Working with in-memory streams often involves turning byte data into text and vice versa. The key points are:

  • Always use the same text encoding for writing and reading.
  • Reset or manage the Position of the stream before reading.
  • Be careful when disposing StreamReader/StreamWriter; use leaveOpen when needed so the MemoryStream remains usable.

Below are practical patterns in C# and VB.NET.

Serialize to JSON and read back as a string (C#)

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;

public static class JsonHelpers
{
    public static string SerializeToJsonString<T>(T value)
    {
        using var ms = new MemoryStream();
        var json = new DataContractJsonSerializer(typeof(T));
        json.WriteObject(ms, value);

        ms.Position = 0; // rewind before reading
        using var reader = new StreamReader(ms, Encoding.UTF8, detectEncodingFromByteOrderMarks: true, bufferSize: 4096, leaveOpen: false);
        return reader.ReadToEnd();
    }
}

// Example
// var text = JsonHelpers.SerializeToJsonString(model);

If you already have a MemoryStream and want a string out of it:

static string ReadAllTextFromMemory(MemoryStream buffer, Encoding? encoding = null)
{
    var enc = encoding ?? Encoding.UTF8;
    long saved = buffer.Position;
    buffer.Position = 0;
    using var reader = new StreamReader(buffer, enc, detectEncodingFromByteOrderMarks: true, bufferSize: 4096, leaveOpen: true);
    string text = reader.ReadToEnd();
    buffer.Position = saved;
    return text;
}

Writing and reading text with MemoryStream (VB.NET)

Imports System.IO
Imports System.Text

Module Module1
    Sub Main()
        Using mem As New MemoryStream()
            ' Keep the stream open when disposing writers/readers
            Using writer As New StreamWriter(mem, Encoding.UTF8, 1024, leaveOpen:=True)
                writer.WriteLine("Hello from VB.NET")
                writer.Flush()
            End Using

            ' Rewind before reading
            mem.Position = 0

            Using reader As New StreamReader(mem, Encoding.UTF8, detectEncodingFromByteOrderMarks:=True, bufferSize:=1024, leaveOpen:=True)
                Dim text = reader.ReadToEnd()
                Console.WriteLine(text)
            End Using
        End Using
    End Sub
End Module

Reading a MemoryStream using the byte array directly

This approach avoids a StreamReader but copies the bytes. It’s simple, but for large buffers, consider reading directly from the stream.

// Encoding must match the bytes inside the stream
string text = Encoding.UTF8.GetString(memoryStream.ToArray());

For slightly less copying (when allowed), you can use the current contents and length:

// Works when the stream is not closed and you accept exposing the internal buffer
string text = Encoding.UTF8.GetString(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);

Read from an arbitrary position and preserve the current cursor (VB.NET)

Imports System.IO
Imports System.Text

Module StreamReadSlice
    Public Function ReadSlice(mem As MemoryStream, Optional offset As Long = 0, Optional enc As Encoding = Nothing) As String
        If enc Is Nothing Then enc = Encoding.UTF8
        Dim original = mem.Position
        mem.Position = Math.Max(0, Math.Min(offset, mem.Length))
        Dim result As String
        Using r As New StreamReader(mem, enc, detectEncodingFromByteOrderMarks:=True, bufferSize:=4096, leaveOpen:=True)
            result = r.ReadToEnd()
        End Using
        mem.Position = original
        Return result
    End Function
End Module

Extensoin method: read entire MemoryStream as text (C#)

using System.IO;
using System.Text;

public static class MemoryStreamReadExtensions
{
    public static string ReadAllText(this MemoryStream stream, Encoding? encoding = null, long start = 0)
    {
        var enc = encoding ?? Encoding.UTF8;
        long saved = stream.Position;
        if (start >= 0) stream.Position = start;
        using var reader = new StreamReader(stream, enc, detectEncodingFromByteOrderMarks: true, bufferSize: 4096, leaveOpen: true);
        string text = reader.ReadToEnd();
        stream.Position = saved;
        return text;
    }
}

Usage:

using var ms = new MemoryStream();
using var w = new StreamWriter(ms, Encoding.UTF8, 1024, leaveOpen: true);
w.Write("sample");
w.Flush();
Console.WriteLine(ms.ReadAllText());

Extension methods to write lines and dump to console (C#)

using System;
using System.IO;
using System.Text;

public static class MemoryStreamWriteExtensions
{
    public static void AppendLine(this MemoryStream stream, string line, Encoding? encoding = null, bool flush = false)
    {
        var enc = encoding ?? Encoding.UTF8;
        byte[] data = enc.GetBytes(line + Environment.NewLine);
        lock (stream) // optional: synchronize when accessed from multiple threads
        {
            stream.Write(data, 0, data.Length);
            if (flush) stream.Flush();
        }
    }

    public static void DumpToConsole(this MemoryStream stream, Encoding? encoding = null)
    {
        var enc = encoding ?? Encoding.UTF8;
        lock (stream)
        {
            long saved = stream.Position;
            stream.Position = 0;
            using var r = new StreamReader(stream, enc, detectEncodingFromByteOrderMarks: true, bufferSize: 4096, leaveOpen: true);
            var text = r.ReadToEnd();
            stream.Position = saved;
            if (!string.IsNullOrEmpty(text))
                Console.WriteLine(text);
        }
    }
}

End-to-end example: serialize to JSON, convert to string, reconstruct stream, and deserialize (C#)

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;

[DataContract]
public class Contact
{
    [DataMember] public int Id { get; set; }
    [DataMember] public string Name { get; set; } = string.Empty;
    [DataMember] public DateTime Created { get; set; }
    [DataMember] public List<Phone> Phones { get; set; } = new();
}

[DataContract]
public class Phone
{
    [DataMember] public PhoneKind Kind { get; set; }
    [DataMember] public string Number { get; set; } = string.Empty;
}

public enum PhoneKind { Home = 1, Mobile = 2 }

public static class JsonRoundtrip
{
    public static string MemoryStreamToString(MemoryStream ms, Encoding? enc = null)
    {
        var e = enc ?? Encoding.UTF8;
        ms.Position = 0;
        using var reader = new StreamReader(ms, e, detectEncodingFromByteOrderMarks: true, bufferSize: 4096, leaveOpen: true);
        return reader.ReadToEnd();
    }

    public static MemoryStream StringToMemoryStream(string s, Encoding? enc = null)
    {
        var e = enc ?? Encoding.UTF8;
        var bytes = e.GetBytes(s);
        return new MemoryStream(bytes, 0, bytes.Length, writable: false, publiclyVisible: true);
    }

    public static void Demo()
    {
        var model = new Contact
        {
            Id = 7,
            Name = "Sample",
            Created = DateTime.UtcNow,
            Phones = new List<Phone>
            {
                new Phone { Kind = PhoneKind.Home,   Number = "555-0100" },
                new Phone { Kind = PhoneKind.Mobile, Number = "555-0200" }
            }
        };

        var serializer = new DataContractJsonSerializer(typeof(Contact));
        using var outbound = new MemoryStream();
        serializer.WriteObject(outbound, model);

        string json = MemoryStreamToString(outbound);
        Console.WriteLine(json);

        using var inbound = StringToMemoryStream(json);
        inbound.Position = 0;
        var model2 = (Contact)serializer.ReadObject(inbound)!;

        Console.WriteLine($"{model2.Id} {model2.Name} {model2.Created:yyyy-MM-dd}");
    }
}

Simple byte[] → MemoryStream → string (C#)

var data = Encoding.ASCII.GetBytes("Alpha - Beta");
using var ms = new MemoryStream(data, writable: false);
using var reader = new StreamReader(ms, Encoding.ASCII, detectEncodingFromByteOrderMarks: false, bufferSize: 1024, leaveOpen: false);
string s = reader.ReadToEnd();

StreamReader with ReadToEnd (C#)

using var ms = new MemoryStream();
using var writer = new StreamWriter(ms, Encoding.UTF8, 1024, leaveOpen: true);
writer.Write("example");
writer.Flush();

ms.Position = 0;
using var reader = new StreamReader(ms, Encoding.UTF8, detectEncodingFromByteOrderMarks: true, bufferSize: 4096, leaveOpen: true);
string text = reader.ReadToEnd();

VB.NET extension: read entire MemoryStream and restore position

Imports System.IO
Imports System.Runtime.CompilerServices
Imports System.Text

Public Module MemoryStreamExtensions
    <Extension>
    Public Function ReadAll(ByVal mem As MemoryStream, Optional ByVal enc As Encoding = Nothing) As String
        If enc Is Nothing Then enc = Encoding.UTF8
        Dim pos = mem.Position
        mem.Position = 0
        Dim value As String
        Using r As New StreamReader(mem, enc, detectEncodingFromByteOrderMarks:=True, bufferSize:=4096, leaveOpen:=True)
            value = r.ReadToEnd()
        End Using
        mem.Position = pos
        Return value
    End Function
End Module

Related Articles

Efficient Usage of HTTP Client in IntelliJ IDEA

IntelliJ IDEA incorporates a versatile HTTP client tool, enabling developres to interact with RESTful services and APIs effectively with in the editor. This functionality streamlines workflows, replac...

Installing CocoaPods on macOS Catalina (10.15) Using a User-Managed Ruby

System Ruby on macOS 10.15 frequently fails to build native gems required by CocoaPods (for example, ffi), leading to errors like: ERROR: Failed to build gem native extension checking for ffi.h... no...

Resolve PhpStorm "Interpreter is not specified or invalid" on WAMP (Windows)

Symptom PhpStorm displays: "Interpreter is not specified or invalid. Press ‘Fix’ to edit your project configuration." This occurs when the IDE cannot locate a valid PHP CLI executable or when the debu...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.