现在的位置: 首页 > 综合 > 正文

用Stream代理bytes[]吧~

2012年02月04日 ⁄ 综合 ⁄ 共 2250字 ⁄ 字号 评论关闭

  网络读取需要buffer, 就是byte[]数组啦。buffer分配后占用固定内存,size设小了不够用,size设大了造成浪费并且频繁创建对性能有影响;

  需要对buffer进行复用,目前了解有2种方式:

1. buffer对象池,WCF就用的此方式;

2. buffer分割,即ArraySegment<byte>;

  无论是上面那种方式,在调用的时候均需要关注buffer,像数组分割还要关心offset等很麻烦。如:

byte[] buffer = new byte[512];
            Stream stream = new MemoryStream();
            stream.Read(buffer, 0, buffer.Length);
            stream.Write(buffer, 0, buffer.Length);

换成复用的方式:

            BufferSegment seg = new BufferSegment();

            byte[] buffer = seg.Take();
            try
            {
                Stream stream = new MemoryStream();
                stream.Read(buffer, 0, buffer.Length);
                stream.Write(buffer, 0, buffer.Length);
            }
            finally
            {
                seg.Return(buffer);
            }

对于调用方来说又依赖了buffer服用对象,即上面的BufferSegment,而且还必须写try-finally,东西没还回去问题就大了,例如SqlConnection的连接池是在.Dispose()时候return连接池的,如果没有.Dispose()就会出现连接不够用的情况。

            BufferSegment seg = new BufferSegment();

            using(Buffer item = seg.Take())
            {
                byte[] buffer = item.Array;
                Stream stream = new MemoryStream();
                stream.Read(buffer, 0, buffer.Length);
                stream.Write(buffer, 0, buffer.Length);
            }

这种方式把take和return都隐藏掉了,但还是对服用对象BufferSegment产生依赖;

 

  偶然发现4.0中Stream加了一个CopyTo方法,于是扩展如下~

public void CopyTo(Stream destination, int bufferSize)

对外只暴露了buffersize,至于buffer怎么来、怎么去都隐藏掉,减少依赖!

public static void FixedCopyTo(this Stream instance, Stream destination, int length, Func<bool> perAction = null)
        {
            Contract.Requires(instance != null && instance.CanRead);
            Contract.Requires(destination != null && destination.CanWrite);

            B buffer;
            BufferSegment.MemoryBuffer.Take(out buffer);
            try
            {
                int read;
                while (length > 0 && (read = instance.Read(buffer.Array, buffer.Offset, Math.Min(buffer.Count, length))) != 0)
                {
                    destination.Write(buffer.Array, buffer.Offset, read);
                    length -= read;
                    if (perAction != null && !perAction())
                    {
                        break;
                    }
                }
            }
            finally
            {
                BufferSegment.MemoryBuffer.Return(ref buffer);
            }
        }

这些逻辑都被隐藏在内部了!!!调用的时候直接copyto 完事。

只里有个遗憾就需要源对象和目标对象都需要包装成Stream,如开头就需要把byte[]包装成MemoryStream,但实际上byte[512] 和 new MemoryStream(byte[512])内存查不了几个字节,

            BufferSegment seg = new BufferSegment();
            byte[] buffer = seg.Take();
            try
            {
                System.Net.Sockets.Socket sock = new System.Net.Sockets.Socket();
                int recv = sock.Receive(buffer);
                Stream stream = new MemoryStream();
                stream.Write(buffer, 0, recv);
            }
            finally
            {
                seg.Return(buffer);
            }

就可以换成

System.Net.Sockets.Socket sock = new System.Net.Sockets.Socket();
            var netStream = new System.Net.Sockets.NetworkStream(sock);
            Stream stream = new MemoryStream();
            netStream.FixedCopyTo(stream);

仔细观察下.netframework 中的对象,加密、压缩文件等都是Stream,这么多对象都受用,多爽~~~

现在我压根都不想碰byte[]了。。  见到它就想转成MemoryStream~

抱歉!评论已关闭.