用Stream代理bytes[]吧~
网络读取需要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~