【问题标题】:Reset or Clear .NET MemoryStream重置或清除 .NET MemoryStream
【发布时间】:2011-01-28 13:50:02
【问题描述】:

.NET MemoryStream 似乎没有 .Reset 或 .Clear 方法。

我正在考虑使用以下代码来完成此操作:

ms.Seek(0, IO.SeekOrigin.Begin)
ms.SetLength(0)

清除或重置现有 .NET MemoryStream 的正确方法是什么?

【问题讨论】:

  • 只是为了解决这个问题。我想他想知道哪种方法可以防止分配内存。理论上,SetLength(0) 应该保留Capacity,而分配new MemoryStream() 应该释放此内存并分配新内存。根据使用情况,可能希望保留内存并重置流的LengthPosition(无论如何,这就是有记忆力的 C++ 程序员的想法)
  • 并且 OP 的代码是合法的。 .Capacity 保留在这些说明之后,因此这是在不必要时避免释放/分配的最佳方法。

标签: .net memorystream


【解决方案1】:

为什么需要重置内存流?你总是可以创建一个新的。或者你可以使用:

memoryStream.SetLength(0);

【讨论】:

  • 这么晚才遇到,但安德鲁是正确的。因为我不得不检查,所以把它留在这里。 MSDN:如果指定的值大于当前容量并且流是可调整大小的,则容量会增加......新旧长度之间的流被初始化为零。
  • 当您将数据重新读取到流中时,这不起作用。位置和长度将为 0!
  • 创建新的内存流会导致分配。有些程序对性能很敏感,每次分配都很重要。
  • @NicFoster memoryStream.SetLength(0) 的目的是什么?我可以再次写入流吗?
  • @silkfire,它会清除内存流,因此您可以重用它,而不是创建一个分配内存的新流(更慢)。
【解决方案2】:

内存流没有重置/清除方法,因为它是多余的。通过将其设置为零长度可以清除它。

当然你总是可以这样做的:

memoryStream = new MemoryStream(memoryStream.Capacity());

这将为您生成与初始化大小相同的内存流。

如果您真的想手动清除流,我怀疑您将不得不求助于循环遍历元素。

【讨论】:

  • -1 当您可以.SetLength(0); 并保留容量时,为什么还要使用相同容量的新流?内存滥用在行动。
  • 如果您使用带有 using 语句的流也不起作用。也更喜欢 .SetLenght(0)
  • 这就是为什么我的回答指出将其设置为零长度会清除它。然后详细说明如何获得由构造函数初始化的相同长度的流。
【解决方案3】:

由于 MemoryStream 本质上是一个带有索引(和一些其他支持成员)的字节数组,因此清除字节数组并重置索引可以视为重置和清除 MemoryStream。如果 MemoryStream 的初始状态是位置为零的归零数组,则 MemoryStream 重置的示例可能是:

public static void Clear(this MemoryStream source)
{
  byte[] buffer = source.GetBuffer();
  Array.Clear(buffer, 0, buffer.Length);
  source.Position = 0;
  source.SetLength(0);
}

说 MemoryStream.SetLength 单独重置或清除 MemoryStream 是不正确的,因为 SetLength 仅在长度超过当前缓冲区的长度时才清除内部缓冲区数组。

重新初始化 MemoryStream 是一种有效的方法,但效率较低。重新初始化 MemoryStream 的一个好处是保证流永远不会关闭。一旦 MemoryStream 关​​闭,就不能再更改它。如果您可以确保 MemoryStream 实例未关闭,那么清除缓冲区可能是可行的方法。

【讨论】:

  • .Reset() 不应该将数据归零吗?只有 .Clear() 应该这样做... PS - 有什么方法可以在流关闭后读取数据长度? (即:希望没有私人反射)
  • 这里只想强调一个重点:如果您直接使用缓冲区,如果您在您将位置重置为零。但是,如果您坚持使用 Read() 方法,这不会发生 - 流“结束”之后的字节不会从一个缓冲区复制到另一个缓冲区。
  • 在调用source.GetBuffer() 时总是为有效的非空流获取异常:无法访问MemoryStream 的内部缓冲区更新:这里解释了原因:stackoverflow.com/a/1646219/44217
  • 设置长度为0也将位置设置为0,所以设置位置是多余的
  • 从安全角度来看,这是最好的答案。例如:当使用带有 CryptoStream 的 MemoryStream 时,您可以确保在完成后立即将内存清零,而不是等待垃圾收集器来释放对象(如果这甚至将字节清零)。
【解决方案4】:

我使用 DotMemory 来分析 @Rana_Ian 解决方案,并调用 GC 来强制执行完整收集。 我发现大型 Streams 会卡在 LOH 中! 再加上一行

public static void Clear(MemoryStream ms)
{
    var buffer = ms.GetBuffer();
    Array.Clear(buffer, 0, buffer.Length);
    ms.Position = 0;
    ms.SetLength(0);
    ms.Capacity = 0; // <<< this one ******
}

我点击F12查看Capacity实现,我发现了这个(我稍微简化了生成的代码 - 我正在使用Resharper):

public virtual int Capacity
{
  get
  { .... // some code }
  set
  {
    if ((long) value < this.Length) { // throw some ex }
    if (!this._isOpen) { // some another code }
    if (!this._expandable && value != this.Capacity) { //MemoryStreamNotExpandable }
    if (!this._expandable || value == this._capacity) return;
    if (value > 0)
    {
      byte[] numArray = new byte[value];
      if (this._length > 0)
        Buffer.InternalBlockCopy((Array) this._buffer, 0, (Array) numArray, 0, this._length);
      this._buffer = numArray;
    }
    else
      this._buffer = (byte[]) null; /// <<<< that's it! I need this one
    this._capacity = value;
  }
}

所以它正在清除缓冲区,我不确定这是否正确!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多