zoukankan      html  css  js  c++  java
  • MemoryStream

    被MemoryStream狠狠地坑了一把

    Stream是.net数据流操作的一个封装,它提供统一的流读写规则,为后期开发这方面的功能提供了很大的便利性.有些场景下是直接操作byte[]比较灵活所以Stream派生出MemoryStream从byte[]构建一个stream来方便开发人员使用.但在使用的时候碰到了一个非常坑爹事情.一个非常意想不到的结果...

    应用代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    string value = "111111111";
                string value1 = "2222222222222222222222";
                System.IO.MemoryStream stream = new System.IO.MemoryStream(mBuffer);
                int count = Encoding.UTF8.GetBytes(value, 0, value.Length, mBuffer, 0);
                stream.Position = 0;
                stream.SetLength(count);
                Console.WriteLine("Length:"+count);
                Console.WriteLine(Encoding.UTF8.GetString(mBuffer, 0, count));
     
                count = Encoding.UTF8.GetBytes(value1, 0, value1.Length, mBuffer, 0);
                stream.Position = 0;
                stream.SetLength(count);
                Console.WriteLine("Length:" + count); ;
                Console.WriteLine(Encoding.UTF8.GetString(mBuffer, 0, count));
                Console.Read();

    以上代码是把不同长度的字符编码到buffer中,然后再设置对应stream的开始位置和长度,从而让stream提供给其他功能使用,比较常见的就是对象反序列化等工作.从代码来看结果输出内容分别value和value1,但最终的运行结果确是

    value1对应的内容少了一截...当出现这问题的时候排查了很久数据跟踪但没发现有任何环节有异常,因为buffer在后期根本没有地方对它进行修改,但数据确发生改变.

    MemoryStream的一个坑

    在跟踪日志来看buffer在经过stream.setlength之前都是好的,但经过这个方法后buffer内容就改变了,后面的代码也没对stream进行任何的操作;所以马上想到地扩容的问题,但由于buffer的长度比较大对应setlength的值也不可能大于buffer分配的长度问题应该不是扩容导致的;无耐之下只好反编译MomeryStream的代码看下,仔细查看MomeryStream的setlength后终于找到问题的根源...

    1
    2
    3
    4
    5
    int num = this._origin + (int)value;
        if (!this.EnsureCapacity(num) && num > this._length)
        {
            Array.Clear(this._buffer, this._length, num - this._length);
        }

    这代码说明了一切问题,在setlength里如果没有导致扩容和大于之前的长度,则会增长部分进行一个清除操作...

    实际应用中使用的代码

    复制代码
     1 namespace MSMQNode.Agent
     2 {
     3     public class ProtoBufFormater : IObjectFormater
     4     {
     5         public object Deserialize(ByteArraySegment content)
     6         {
     7             object result;
     8             try
     9             {
    10                 content.SetPostion(0);
    11                 string text = content.ReadShortString(Encoding.UTF8);
    12                 Type type = Type.GetType(text);
    13                 if (type == null)
    14                 {
    15                     throw MQError.TYPE_NOTFOUND(text);
    16                 }
    17                 object obj = Activator.CreateInstance(type);
    18                 Stream stream = content.GetStream();
    19                 stream.Position = (long)content.Postion;
    20                 stream.SetLength((long)content.Count);
    21                 obj = RuntimeTypeModel.Default.Deserialize(stream, null, type);
    22                 result = obj;
    23             }
    24             catch (Exception error)
    25             {
    26                 throw new MQMessageFormatError("Deserialize Error!", error);
    27             }
    28             return result;
    29         }
    30         public ByteArraySegment Serialize(object message)
    31         {
    32             ByteArraySegment byteArraySegment = HttpDataPackage.BufferPool.Pop();
    33             try
    34             {
    35                 Type type = message.GetType();
    36                 string typeName = Utils.GetTypeName(type);
    37                 byteArraySegment.WriteShortString(typeName, Encoding.UTF8);
    38                 Stream stream = byteArraySegment.GetStream();
    39                 stream.Position = (long)byteArraySegment.Postion;
    40                 stream.SetLength((long)byteArraySegment.Postion);
    41                 RuntimeTypeModel.Default.Serialize(stream, message);
    42                 byteArraySegment.SetInfo(0, (int)stream.Length);
    43             }
    44             catch (Exception error)
    45             {
    46                 HttpDataPackage.BufferPool.Push(byteArraySegment);
    47                 throw new MQMessageFormatError("Serialize Error!", error);
    48             }
    49             return byteArraySegment;
    50         }
    51     }
    52 }
    复制代码

    总结

    真的搞不明白为什么要这样设计,既然Length是可设置的即说明可以由开发人员指定现在流的内容长度,开发人员在设置之也会意识到相应buffer的数据信息.更何况Length的改变并不会更改postion位置,在后面对Stream的写入自然会把之前的内容代替.

    如果那位同学以后要这样使用MemoryStream就要注意一下了:)

  • 相关阅读:
    mysql中如何根据id,一次查询对应id的数据
    DataFrame中merge、concat、join,以及用一个data更新另一个data的方法
    pandas中drop_duplicates用法
    DataFrame中根据某字段选取重复字段数据
    金融数据处理过程中的一些小tip
    pandas中某一列的值满足一定条件就改变
    MIKE指标
    python 数据处理中的记录
    python绘制主次坐标图
    python学习笔记之四-多进程&多线程&异步非阻塞
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3106267.html
Copyright © 2011-2022 走看看