ZetCode

C# MemoryStream

last modified April 20, 2025

This tutorial explains how to use the MemoryStream class in C# for in-memory stream operations. MemoryStream provides a stream interface for working with data in memory.

The MemoryStream class creates a stream that uses memory as storage instead of a disk or network connection. It inherits from the Stream class.

MemoryStream is useful when you need stream functionality but want to avoid disk I/O. It's commonly used for temporary storage, data manipulation, and as an intermediate buffer.

Basic MemoryStream Example

This example demonstrates creating a MemoryStream and writing some bytes to it. We then read the data back from the stream.

Program.cs
using System;
using System.IO;
using System.Text;

class Program
{
    static void Main()
    {
        // Create a MemoryStream
        using (MemoryStream stream = new MemoryStream())
        {
            // Write data to the stream
            byte[] data = Encoding.UTF8.GetBytes("Hello MemoryStream!");
            stream.Write(data, 0, data.Length);
            
            // Reset position to read from beginning
            stream.Position = 0;
            
            // Read data back
            byte[] buffer = new byte[stream.Length];
            stream.Read(buffer, 0, buffer.Length);
            
            string text = Encoding.UTF8.GetString(buffer);
            Console.WriteLine(text);
        }
    }
}

The example creates a MemoryStream, writes a string as bytes, then reads it back. The Position property is reset to 0 before reading to start from the beginning.

MemoryStream implements IDisposable, so we use it in a using statement. The stream automatically expands as needed when writing data. The example shows the basic write-read cycle that's common with MemoryStream operations.

Reading and Writing Primitive Types

MemoryStream can be used with BinaryWriter and BinaryReader to handle primitive data types. This example shows how to write and read different types.

Program.cs
using System;
using System.IO;

class Program
{
    static void Main()
    {
        using (MemoryStream stream = new MemoryStream())
        {
            // Write data using BinaryWriter
            using (BinaryWriter writer = new BinaryWriter(stream, Encoding.UTF8, true))
            {
                writer.Write(42);
                writer.Write(3.14159);
                writer.Write(true);
                writer.Write("C# MemoryStream");
            }
            
            // Reset position to read
            stream.Position = 0;
            
            // Read data using BinaryReader
            using (BinaryReader reader = new BinaryReader(stream, Encoding.UTF8, true))
            {
                Console.WriteLine(reader.ReadInt32());
                Console.WriteLine(reader.ReadDouble());
                Console.WriteLine(reader.ReadBoolean());
                Console.WriteLine(reader.ReadString());
            }
        }
    }
}

BinaryWriter and BinaryReader provide convenient methods for primitive types. The stream is passed to their constructors, leaving the stream open for further use.

Note the true parameter in the BinaryWriter/BinaryReader constructors. This keeps the stream open after the writer/reader is disposed. The data is written sequentially and must be read in the same order.

Converting MemoryStream to Byte Array

MemoryStream can easily convert its contents to a byte array. This example shows how to get the underlying byte array from a MemoryStream.

Program.cs
using System;
using System.IO;
using System.Text;

class Program
{
    static void Main()
    {
        // Create and write to MemoryStream
        using (MemoryStream stream = new MemoryStream())
        {
            string text = "This will be converted to a byte array";
            byte[] data = Encoding.UTF8.GetBytes(text);
            stream.Write(data, 0, data.Length);
            
            // Get the byte array
            byte[] byteArray = stream.ToArray();
            
            Console.WriteLine($"Byte array length: {byteArray.Length}");
            Console.WriteLine($"Content: {Encoding.UTF8.GetString(byteArray)}");
        }
    }
}

The ToArray method creates a new byte array containing the stream's data. This is useful when you need to pass the data to methods expecting byte arrays.

The example writes a string to the stream, then converts it to a byte array. The original stream remains unchanged. This operation is efficient as it directly accesses the internal buffer.

Using MemoryStream with StreamWriter/Reader

MemoryStream can work with text-oriented StreamWriter and StreamReader classes. This example demonstrates text-based operations.

Program.cs
using System;
using System.IO;
using System.Text;

class Program
{
    static void Main()
    {
        using (MemoryStream stream = new MemoryStream())
        {
            // Write text using StreamWriter
            using (StreamWriter writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
            {
                writer.WriteLine("First line of text");
                writer.WriteLine("Second line of text");
                writer.Flush();
                
                // Reset position to read
                stream.Position = 0;
                
                // Read text using StreamReader
                using (StreamReader reader = new StreamReader(stream, Encoding.UTF8, false, 1024, true))
                {
                    string line;
                    while ((line = reader.ReadLine()) != null)
                    {
                        Console.WriteLine(line);
                    }
                }
            }
        }
    }
}

StreamWriter and StreamReader handle text encoding and provide line-based operations. The Flush call ensures all buffered data is written to the stream.

The example shows how to chain stream operations. The leaveOpen parameter is set to true to keep the MemoryStream available after the writer is disposed. This pattern is common when working with layered stream operations.

MemoryStream with Initial Capacity

MemoryStream can be initialized with a specific capacity to optimize performance. This example shows how to use the capacity constructor.

Program.cs
using System;
using System.IO;

class Program
{
    static void Main()
    {
        // Create with initial capacity of 1KB
        using (MemoryStream stream = new MemoryStream(1024))
        {
            Console.WriteLine($"Initial capacity: {stream.Capacity}");
            
            // Write data until we exceed capacity
            byte[] data = new byte[512];
            for (int i = 0; i < 5; i++)
            {
                stream.Write(data, 0, data.Length);
                Console.WriteLine($"Capacity after write {i+1}: {stream.Capacity}");
            }
        }
    }
}

Setting an initial capacity can prevent unnecessary reallocations. The stream will automatically expand when needed, but this has performance overhead.

The example shows how the capacity grows as data is written. The initial capacity is 1024 bytes. After writing 2.5KB of data, the capacity has doubled to accommodate the new data. This demonstrates the automatic resizing behavior.

MemoryStream as Buffer for Network Operations

MemoryStream is often used as a buffer for network operations. This example simulates receiving chunks of data and assembling them in a MemoryStream.

Program.cs
using System;
using System.IO;
using System.Text;

class Program
{
    static void Main()
    {
        // Simulate receiving data chunks
        byte[][] chunks = {
            Encoding.UTF8.GetBytes("This is "),
            Encoding.UTF8.GetBytes("a multi-chunk "),
            Encoding.UTF8.GetBytes("message assembled "),
            Encoding.UTF8.GetBytes("in MemoryStream")
        };
        
        using (MemoryStream stream = new MemoryStream())
        {
            // Process each chunk
            foreach (byte[] chunk in chunks)
            {
                Console.WriteLine($"Processing {chunk.Length} byte chunk");
                stream.Write(chunk, 0, chunk.Length);
            }
            
            // Get complete message
            stream.Position = 0;
            using (StreamReader reader = new StreamReader(stream))
            {
                Console.WriteLine("Complete message:");
                Console.WriteLine(reader.ReadToEnd());
            }
        }
    }
}

MemoryStream is ideal for assembling data from multiple sources. It provides the flexibility to write data as it arrives and read it when complete.

The example simulates receiving data in chunks over a network. Each chunk is written to the MemoryStream as it arrives. Finally, the complete message is read from the stream. This pattern is common in network programming.

MemoryStream for Image Manipulation

MemoryStream is commonly used with image processing. This example shows how to load an image into a MemoryStream and then save it to a file.

Program.cs
using System;
using System.IO;
using System.Drawing;

class Program
{
    static void Main()
    {
        // Load an image file into MemoryStream
        byte[] imageBytes = File.ReadAllBytes("input.jpg");
        
        using (MemoryStream stream = new MemoryStream(imageBytes))
        {
            // Process the image in memory
            using (Image image = Image.FromStream(stream))
            {
                Console.WriteLine($"Image size: {image.Width}x{image.Height}");
                
                // Save to a new file (simulating processing)
                image.Save("output.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
            }
        }
        
        Console.WriteLine("Image processed and saved");
    }
}

MemoryStream allows image processing without multiple disk operations. The image is loaded once into memory and can be processed efficiently.

The example reads an image file into a byte array, then creates a MemoryStream from it. The Image class can load directly from the stream. This approach is useful when working with images from databases or network sources.

Source

MemoryStream Class Documentation

This tutorial covered using MemoryStream in C# for various scenarios including basic operations, primitive types, text handling, buffering, and image processing.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all C# tutorials.