zoukankan      html  css  js  c++  java
  • 关于MemoryStream类

    许多人认为MemoryStream是无法进行扩展的,其实不然;为了更好了解MemoryStream,我不得不研究MemoryStream的源代码,首先看空构造函数(以下代码均是Reflector Pro版本反射得到):

    [C#]

    public MemoryStream() : this(0)
    {
    }

    public MemoryStream(int capacity)
    {
    if (capacity < 0)
    {
    throw new ArgumentOutOfRangeException("capacity", Environment.GetResourceString("ArgumentOutOfRange_NegativeCapacity"));
    }
    this._buffer = new byte[capacity];
    this._capacity = capacity;
    this._expandable = true;
    this._writable = true;
    this._exposable = true;
    this._origin = 0;
    this._isOpen = true;
    }

    [VB.NET]

    Public Sub New()
    Me.New(0)
    End Sub

    Public Sub New(ByVal capacity As Integer)
    If (capacity < 0) Then
    Throw New ArgumentOutOfRangeException("capacity", Environment.GetResourceString("ArgumentOutOfRange_NegativeCapacity"))
    End If
    Me._buffer = New Byte(capacity - 1) {}
    Me._capacity = capacity
    Me._expandable = True
    Me._writable = True
    Me._exposable = True
    Me._origin = 0
    Me._isOpen = True
    End Sub

    从代码中可以知道——MemoryStream内部存放的一个内存数组,当空构造函数的时候,该数组的实际容量为0;然后调用Write函数的时候……

    [C#]

    public override void Write(byte[] buffer, int offset, int count)
    {
    //省去其它部分……
        int num = this._position + count;
        if (num > this._length)
    {
    bool flag = this._position > this._length;
    if ((num > this._capacity) && this.EnsureCapacity(num))
    {
    flag = false;
    }
    if (flag)
    {
    Array.Clear(this._buffer, this._length, num - this._length);
    }
    this._length = num;
    }
    if ((count <= 8) && (buffer != this._buffer))
    {
    int num2 = count;
    while (--num2 >= 0)
    {
    this._buffer[this._position + num2] = buffer[offset + num2];
    }
    }
    else
    {
    Buffer.InternalBlockCopy(buffer, offset, this._buffer, this._position, count);
    }
    this._position = num;
    }

    [VB.NET]

    Public Overrides Sub Write(buffer__1 As Byte(), offset As Integer, count As Integer)
    '省去其它部分……
    Dim num As Integer = (Me._position + count)
        If num > Me._length Then
    Dim flag As Boolean = Me._position > Me._length
    If (num > Me._capacity) AndAlso Me.EnsureCapacity(num) Then
    flag = False
    End If
    If flag Then
    Array.Clear(Me._buffer, Me._length, num - Me._length)
    End If
    Me._length = num
    End If
    If (count <= 8) AndAlso (buffer<> Me._buffer) Then
    Dim num2 As Integer = count
            Do While (--num2 >= 0)
                Me._buffer((Me._position + num2)) = buffer((offset + num2))
            Loop
        Else
    Buffer.InternalBlockCopy(buffer__1, offset, Me._buffer, Me._position, count)
    End If
    Me._position = num
    End Sub

    以上代码大致的意思是:先检测内部剩余空间是否足够容纳外部buffer要写入的字节数(count),如果探测发现内部数组剩余空间不够的话,那么自动扩容——请注意EnsureCapacity函数,反编译结果如下:
    [C#]

    private bool EnsureCapacity(int value)
    {
    if (value < 0)
    {
    throw new IOException(Environment.GetResourceString("IO.IO_StreamTooLong"));
    }
    if (value <= this._capacity)
    {
    return false;
    }
    int num = value;
    if (num < 0x100)
    {
    num = 0x100;
    }
    if (num < (this._capacity * 2))
    {
    num = this._capacity * 2;
    }
    this.Capacity = num;
    return true;
    }

    [VB.NET]

    从反编译结果可以明显看到,MemoryStream在使用第一、第二构造函数的时候(指定capability的时候,非直接传入一个byte数组的时候)是可以进行扩容的。扩容情况如下:

    1)当实际需要的容量小于256个字节,自动扩容到256;

    2)当实际需要的容量小于实际容量的2倍的时候,自动扩容到自身容量的2倍。

    而真正扩容的地方在属性Capacity中——

    [C#]

    public virtual int Capacity
    {
    //省略其它部分……
    if (this._expandable && (value != this._capacity))
    {
    if (value > 0)
    {
    byte[] dst = new byte[value];
    if (this._length > 0)
    {
    Buffer.InternalBlockCopy(this._buffer, 0, dst, 0, this._length);
    }
    this._buffer = dst;
    }
    else
    {
    this._buffer = null;
    }
    this._capacity = value;
    }
    }
    }

    [VB.NET]

    Public Overridable Property Capacity As Integer
    '省略其它部分……

    If (Me._expandable AndAlso (value <> Me._capacity)) Then
    If (value > 0) Then
    Dim dst As Byte() = New Byte(value - 1) {}
    If (Me._length > 0) Then
    Buffer.InternalBlockCopy(Me._buffer, 0, dst, 0, Me._length)
    End If
    Me._buffer = dst
    Else
    Me._buffer = Nothing
    End If
    Me._capacity = value
    End If
    End Set
    End Property


    可见,.NET类库做的是“先生成新数组,然后使用内部底层的InteralBlockCopy进行批量拷贝。不过请注意————expandable是一个条件,该条件决定MemoryStream是否允许扩容,而这个私有变量在MemoryStream上面给出的两个构造函数中充分显示了。因此只有在使用MemoryStream的第一、二构造函数的时候才允许扩容,其余时候都是不允许的(因为默认expandable=false,布尔值默认是false)。

  • 相关阅读:
    案例分享:Qt+Arm基于RV1126平台的内窥镜软硬整套解决方案(实时影像、冻结、拍照、录像、背光调整、硬件光源调整,其他产品也可使用该平台,如视频监控,物联网产品等等)
    libzip开发笔记(二):libzip库介绍、ubuntu平台编译和工程模板
    案例分享:Qt西门子机床人机界面以及数据看板定制(西门子通讯,mysql数据库,生产信息,参数信息,信息化看板,权限控制,播放器,二维图表,参数调试界面)
    sshpass 简介
    SSH 协议及 OpenSSH 实现
    Linux从头学07:中断那么重要,它的本质到底是什么?
    Linux从头学06:16张结构图,彻底理解【代码重定位】的底层原理
    Linux从头学05-系统启动过程中的几个神秘地址,你知道是什么意思吗?
    所有编程语言中的栈操作,底层原理都在这里
    WSL2:Windows 亲生的 Linux 子系统
  • 原文地址:https://www.cnblogs.com/ServiceboyNew/p/2337148.html
Copyright © 2011-2022 走看看