ZetCode

C# MemoryStream

最后修改于 2025 年 4 月 20 日

本教程介绍如何在 C# 中使用 MemoryStream 类进行内存流操作。MemoryStream 提供了一个流接口,用于处理内存中的数据。

MemoryStream 类创建一个使用内存作为存储的流,而不是磁盘或网络连接。它继承自 Stream 类。

当您需要流功能但又想避免磁盘 I/O 时,MemoryStream 非常有用。它通常用于临时存储、数据操作以及作为中间缓冲区。

MemoryStream 基础示例

此示例演示了创建 MemoryStream 并向其写入一些字节。 然后,我们从流中读回数据。

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);
        }
    }
}

该示例创建了一个 MemoryStream,将一个字符串作为字节写入,然后将其读回。 在读取之前,Position 属性将重置为 0,以便从头开始。

MemoryStream 实现了 IDisposable,因此我们在 using 语句中使用它。 写入数据时,流会自动扩展。 该示例显示了 MemoryStream 操作中常见的基本写入-读取循环。

读取和写入基本类型

MemoryStream 可以与 BinaryWriter 和 BinaryReader 一起使用来处理基本数据类型。 此示例演示如何写入和读取不同的类型。

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 和 BinaryReader 为基本类型提供了便捷的方法。 流被传递给它们的构造函数,保持流打开以供进一步使用。

请注意 BinaryWriter/BinaryReader 构造函数中的 true 参数。 这会在写入器/读取器被释放后保持流打开。 数据按顺序写入,并且必须按相同的顺序读取。

将 MemoryStream 转换为字节数组

MemoryStream 可以轻松地将其内容转换为字节数组。 此示例演示如何从 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)}");
        }
    }
}

ToArray 方法创建一个包含流数据的新字节数组。 当您需要将数据传递给期望字节数组的方法时,这非常有用。

该示例将一个字符串写入流,然后将其转换为字节数组。 原始流保持不变。 此操作非常有效,因为它直接访问内部缓冲区。

将 MemoryStream 与 StreamWriter/Reader 一起使用

MemoryStream 可以与面向文本的 StreamWriter 和 StreamReader 类一起使用。 此示例演示了基于文本的操作。

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 和 StreamReader 处理文本编码并提供基于行的操作。 Flush 调用确保所有缓冲数据都写入流。

该示例演示了如何链接流操作。 leaveOpen 参数设置为 true,以在写入器被释放后保持 MemoryStream 可用。 这种模式在使用分层流操作时很常见。

具有初始容量的 MemoryStream

可以使用特定容量初始化 MemoryStream 以优化性能。 此示例演示如何使用容量构造函数。

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}");
            }
        }
    }
}

设置初始容量可以防止不必要的重新分配。 流将在需要时自动扩展,但这会带来性能开销。

该示例显示了容量如何随着数据的写入而增长。 初始容量为 1024 字节。 写入 2.5KB 数据后,容量已加倍以适应新数据。 这演示了自动调整大小的行为。

MemoryStream 作为网络操作的缓冲区

MemoryStream 通常用作网络操作的缓冲区。 此示例模拟接收数据块并在 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 非常适合从多个来源组装数据。 它提供了在数据到达时写入数据并在完成后读取数据的灵活性。

该示例模拟通过网络以块的形式接收数据。 每个块在到达时都会写入 MemoryStream。 最后,从流中读取完整消息。 这种模式在网络编程中很常见。

MemoryStream 用于图像处理

MemoryStream 通常用于图像处理。 此示例演示如何将图像加载到 MemoryStream 中,然后将其保存到文件。

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 允许图像处理,而无需多次磁盘操作。 图像一次加载到内存中,并且可以高效地处理。

该示例将图像文件读取到字节数组中,然后从中创建一个 MemoryStream。 Image 类可以直接从流中加载。 当处理来自数据库或网络源的图像时,此方法非常有用。

来源

MemoryStream 类文档

本教程介绍了如何在 C# 中使用 MemoryStream 处理各种场景,包括基本操作、基本类型、文本处理、缓冲和图像处理。

作者

我叫 Jan Bodnar,是一位充满热情的程序员,拥有丰富的编程经验。 自 2007 年以来,我一直在撰写编程文章。 迄今为止,我已经撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 C# 教程