MemoryStream 用来干啥?不是所有场景都适合
MemoryStream 是把内存当“文件”用的流,适合小到中等数据的临时读写——比如序列化对象、拼接字节数组、处理 HTTP 响应体、生成 Excel/PDF 内存流。它不持久、不线程安全(默认)、不自动释放资源,拿它读 GB 级文件或长期持有引用,容易触发
OutOfMemoryException或内存泄漏。
常见误用:用
MemoryStream缓存 Web API 的大文件响应后直接返回给前端(该用
FileStream或流式传输);或在 ASP.NET Core 中把
MemoryStream存进静态集合长期持有。
创建和写入 MemoryStream 的三种典型方式
关键点:是否预分配容量、是否允许扩展、写完要不要重置位置。
空构造函数new MemoryStream():内部缓冲区动态增长,但频繁扩容有性能开销;写完要调
stream.Position = 0才能读 带容量的构造函数
new MemoryStream(int capacity):预分配缓冲区,避免多次 realloc;容量只是初始值,仍可自动扩展 传入字节数组
new MemoryStream(byte[] buffer):创建的是“可读写视图”,修改会影响原数组;若只读,用
new MemoryStream(byte[], false)防误写
byte[] data = Encoding.UTF8.GetBytes("hello");
using var stream = new MemoryStream(data, writable: false); // 只读视图
// stream.Write(...) 会抛 NotSupportedException
读取时 Position 和 GetBuffer 的坑
Position是当前读/写偏移,
Length是实际数据长度,
Capacity是已分配缓冲区大小——三者常不相等。尤其注意
GetBuffer()返回的是整个底层数组,不是有效数据部分。 读取全部内容推荐用
ToArray()(安全、返回精确字节),不是
GetBuffer()
GetBuffer()只在你明确需要复用缓冲区且知道
Length边界时才用,否则可能读到脏数据 写入后没调
Position = 0就读,会得到空结果(因为指针在末尾)
using var stream = new MemoryStream();
stream.Write(Encoding.UTF8.GetBytes("test"));
Console.WriteLine(stream.Length); // 输出 4
Console.WriteLine(stream.GetBuffer().Length); // 可能是 256 或更大(内部扩容后的容量)
Console.WriteLine(stream.ToArray().Length); // 稳定输出 4
配合 BinaryWriter / BinaryReader 或序列化使用
MemoryStream 经常作为二进制序列化的载体,但要注意编码一致性与生命周期管理。
用BinaryWriter写完别忘了
Flush()(虽然
Dispose也会刷,但显式更清晰) 反序列化时,确保
MemoryStream.Position == 0,否则
BinaryReader从中间开始读会失败 JSON.NET 或 System.Text.Json 序列化到
MemoryStream时,记得用
Utf8JsonWriter直接写入,避免中间转
string造成额外 GC
真正容易被忽略的是:在异步方法里用
MemoryStream,别把它传给多个并发任务共享操作——没有内置锁,
Position竞态会导致读写错乱。
