重用内存流

31
假设我已经使用以下方法将字节缓冲区复制到内存流中:

Assume I have copied a byte buffer into a memory stream using this

memoryStream.Read(data, 0, data.Length);

有没有办法清空流并重用它来读取其他数据?

我想避免创建许多MemoryStream对象,而是更喜欢使用一个实例,在使用之间重置它。

4个回答

51

您可以通过将流的位置(Position)设置为0且长度(Length)设置为0来重复使用MemoryStream。

MemoryStream ms = new MemoryStream();

// Do some stuff with the stream

// Reset the stream so you can re-use it
ms.Position = 0; // Not actually needed, SetLength(0) will reset the Position anyway
ms.SetLength(0);

// Do some more stuff with the stream

将长度设置为0并不会清除现有缓冲区,它只会重置内部计数器。因此,现有的缓冲区分配保持不变,但所有关于缓冲区使用量的记录都被重置,这样您就可以重新使用它。

更新:我刚刚快速查看了SetLength的代码实现,如果将长度设置为0,则Position属性会自动重置为0,因此您甚至不需要显式设置Position属性,仅重置长度即可。


17

您可以将Position设置为0,这将有效地重置流。

然而,正如答案所示,重用内存流不太可能带来任何性能优势。更好的方法是创建更多的内存流,这样更为经济。

另一种选择是使用固定的byte[]作为重复使用的缓冲区。


1
当然可以 - 但是如果流已经包含100个字节,而我只写了99个字节,那么当我来读取这个流的内容时,我会读取太多的内容 :) - Jack Kada
1
@CycleMachine - 重置/清除内存流不是内置的原因是有其道理的。请参阅我添加的链接答案。 - Oded
6
如果你分配了一个大缓冲区,重复利用缓冲区会比每次重新分配更有效率。使用SetLength(0)而不是设置位置(请参见下面的我的答案),这将保持缓冲区已分配并重置内部计数器、长度和位置,这比频繁重新分配一个大缓冲区更加节省成本。 - Chris Taylor
3
正确答案是 SetLength(0)。这个回答是不正确的。 - James
1
这个答案是错误的。Position 只设置读写位置,但保持数据流中数据的长度不变。所以,后续的读操作会再次给你已经写入到数据流中的数据。使用 SetLength(0) 重置二者。链接中的答案也是错误的。 SetLength(0) 确实重置了长度和位置,并且保留了缓冲区。 - Holger Böhnke
显示剩余2条评论

0

如果您使用memoryStream.getBuffer()和偏移量/长度(使用memoryStream.PositionmemoryStream.Length检测边界)直接访问byte[]数据,Reader/Writer/BinaryFormatter类或其他接受Stream的类,用于将原始/复杂类型读入/写入缓冲区(这就是MemoryStream的作用),您可以避免无用的复制操作,因为MemoryStream已经基于字节数组。

我在异步发送/接收套接字操作中以这种方式使用它来接受byte[],但请注意-如果您在超出当前Length的缓冲区中写入了一些内容,并希望通过SetLength()增加其长度以便使用Reader类进行读取-您会得到非常不方便的行为(在我看来)-如果长度增加,此方法会将旧长度和新长度之间的每个字节都置零。

我通过修改MemoryStream的源代码(在SetLength()中调用了一个Array.Clear,并添加了一些管理.NET内部类的内容)来解决这个问题,并在我的项目中使用它。

关于重用MemoryStream,我同意Chris Taylor的回答(SetLength(0)


-3

memoryStream.Seek(0, SeekOrigin.Begin);


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接