在C#的开发场景中,经常需要处理数据的流式读写,当不需要将数据持久化到磁盘,仅需要在内存中完成流操作时,MemoryStream就是非常合适的选择。它继承自Stream类,所有数据都存储在内存缓冲区中,操作效率远高于磁盘流。

MemoryStream基础概念
MemoryStream是System.IO命名空间下的一个类,用于在内存中创建和操作流。它的核心特点是不依赖外部存储设备,所有读写操作都在内存的字节数组中完成,因此速度非常快,适合临时存储和处理数据。
MemoryStream的常用属性包括:
- CanRead:指示当前流是否支持读取操作
- CanWrite:指示当前流是否支持写入操作
- Length:获取流中数据的总长度,单位为字节
- Position:获取或设置当前流中的读取或写入位置
- Capacity:获取或设置流的内存缓冲区容量
MemoryStream常用方法
MemoryStream提供了和Stream基类一致的常用方法,以下是开发中最常使用的几个:
- Write(byte[] buffer, int offset, int count):将字节数组的数据写入流中
- Read(byte[] buffer, int offset, int count):从流中读取指定长度的字节到字节数组
- Seek(long offset, SeekOrigin origin):设置流的当前位置
- ToArray():将流中的所有数据复制到新的字节数组中
- GetBuffer():返回流底层的内存缓冲区引用(需要注意缓冲区可能未完全使用)
- Flush():清除流的缓冲区,将所有缓冲数据写入基础设备(内存流中此操作无实际效果)
- Close()/Dispose():释放流占用的资源,建议配合using语句使用
基础使用示例
写入和读取字符串数据
最常见的场景是将字符串转换为字节写入MemoryStream,再从流中读取还原为字符串:
using System;
using System.IO;
using System.Text;
class Program
{
static void Main()
{
// 要写入的字符串
string content = "这是一段测试文本,用于演示MemoryStream的基础操作";
// 将字符串转换为字节数组,使用UTF8编码
byte[] writeBytes = Encoding.UTF8.GetBytes(content);
// 使用using语句自动释放MemoryStream资源
using (MemoryStream ms = new MemoryStream())
{
// 将字节数组写入流
ms.Write(writeBytes, 0, writeBytes.Length);
// 将流的位置重置到开头,方便后续读取
ms.Seek(0, SeekOrigin.Begin);
// 创建读取用的字节数组,长度为流的长度
byte[] readBytes = new byte[ms.Length];
// 从流中读取数据到字节数组
int readCount = ms.Read(readBytes, 0, readBytes.Length);
// 将读取的字节数组转换为字符串
string result = Encoding.UTF8.GetString(readBytes, 0, readCount);
Console.WriteLine("读取到的内容:" + result);
}
}
}
直接获取流中的字节数组
如果需要直接获取MemoryStream中存储的所有数据,可以使用ToArray方法:
using System;
using System.IO;
using System.Text;
class Program
{
static void Main()
{
string data = "测试ToArray方法的使用";
byte[] sourceBytes = Encoding.UTF8.GetBytes(data);
using (MemoryStream ms = new MemoryStream())
{
ms.Write(sourceBytes, 0, sourceBytes.Length);
// 直接获取流中所有数据的字节数组
byte[] allBytes = ms.ToArray();
string result = Encoding.UTF8.GetString(allBytes);
Console.WriteLine("通过ToArray获取的内容:" + result);
}
}
}
进阶使用场景
配合其他流完成数据转换
MemoryStream经常和其他流配合使用,比如将图片数据读取后临时存储在内存流中,再进行后续处理:
using System;
using System.IO;
class Program
{
static void Main()
{
// 模拟从其他来源获取的图片字节数据
byte[] imageSourceBytes = new byte[] { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A }; // PNG文件头示例
using (MemoryStream ms = new MemoryStream())
{
// 将图片数据写入内存流
ms.Write(imageSourceBytes, 0, imageSourceBytes.Length);
// 重置流位置
ms.Position = 0;
// 这里可以将内存流传递给其他需要处理流的方法,比如图片处理、文件上传等
ProcessStream(ms);
}
}
static void ProcessStream(Stream stream)
{
Console.WriteLine("处理流数据,流长度:" + stream.Length);
// 实际场景中这里会进行具体的流处理逻辑
}
}
初始化时指定容量和初始数据
MemoryStream的构造函数支持指定初始容量和初始数据,适合已知数据规模的场景:
using System;
using System.IO;
using System.Text;
class Program
{
static void Main()
{
// 指定初始容量为1024字节
using (MemoryStream ms1 = new MemoryStream(1024))
{
Console.WriteLine("初始容量:" + ms1.Capacity);
}
// 指定初始数据
byte[] initData = Encoding.UTF8.GetBytes("初始数据");
using (MemoryStream ms2 = new MemoryStream(initData))
{
// 流初始位置为0,已经包含初始数据
byte[] readBytes = new byte[ms2.Length];
ms2.Read(readBytes, 0, readBytes.Length);
Console.WriteLine("初始数据内容:" + Encoding.UTF8.GetString(readBytes));
}
}
}
使用注意事项
- MemoryStream的数据存储在内存中,如果存储大量数据会导致内存占用过高,不适合处理超大文件
- 使用完MemoryStream后一定要及时释放资源,推荐使用using语句自动调用Dispose方法
- 调用GetBuffer方法时,返回的缓冲区长度可能大于实际存储的数据长度,需要结合Length属性判断有效数据范围
- 如果需要多次读写,注意及时重置Position属性,否则会出现读取不到数据或者数据不完整的问题
- MemoryStream不支持异步操作的传统Begin/End模式,但支持基于Task的异步方法如ReadAsync、WriteAsync
和FileStream的对比
很多开发者会混淆MemoryStream和FileStream的使用场景,两者的核心区别如下:
| 对比项 | MemoryStream | FileStream |
|---|---|---|
| 存储位置 | 内存缓冲区 | 磁盘文件 |
| 操作速度 | 快 | 慢 |
| 数据持久性 | 程序结束后数据丢失 | 数据持久化保存 |
| 适用场景 | 临时数据处理、内存数据流转 | 文件读写、持久化存储 |
| 资源占用 | 占用内存 | 占用磁盘空间,需要文件句柄 |
C#MemoryStream内存流操作流处理修改时间:2026-07-21 14:48:38