好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

MemoryStream

MemoryStream

被MemoryStream狠狠地坑了一把

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

应用代码

?

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后终于找到问题的根源...

?

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就要注意一下了:)

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于MemoryStream的详细内容...

  阅读:60次