using System; using System.Buffers; using System.Collections; using System.Collections.Generic; using System.IO; using System.Runtime.CompilerServices; namespace Masuit.Tools.Systems; /// /// 池化内存流 /// public sealed class PooledMemoryStream : Stream, IEnumerable { /// /// 终结器 /// ~PooledMemoryStream() { Dispose(true); } private const float OverExpansionFactor = 2; private byte[] _data = { }; private int _length; private readonly ArrayPool _pool; private bool _isDisposed; public PooledMemoryStream() : this(ArrayPool.Shared) { } public PooledMemoryStream(byte[] buffer) : this(ArrayPool.Shared, buffer.Length) { Buffer.BlockCopy(buffer, 0, _data, 0, buffer.Length); _length = buffer.Length; } public PooledMemoryStream(ArrayPool arrayPool, int capacity = 0) { _pool = arrayPool ?? throw new ArgumentNullException(nameof(arrayPool)); if (capacity > 0) { _data = _pool.Rent(capacity); } } public override bool CanRead => true; public override bool CanSeek => true; public override bool CanWrite => true; public override long Length => _length; public override long Position { get; set; } public long Capacity => _data?.Length ?? 0; #if NETCOREAPP || NET452 public Span GetSpan() { return _data.AsSpan(0, _length); } public Memory GetMemory() { return _data.AsMemory(0, _length); } public ArraySegment ToArraySegment() { return new ArraySegment(_data, 0, (int)Length); } #endif public override void Flush() { AssertNotDisposed(); } /// /// 读取到字节数组 /// /// /// /// /// public override int Read(byte[] buffer, int offset, int count) { AssertNotDisposed(); if (count == 0) { return 0; } var available = Math.Min(count, Length - Position); Array.Copy(_data, Position, buffer, offset, available); Position += available; return (int)available; } /// /// 改变游标位置 /// /// /// /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public override long Seek(long offset, SeekOrigin origin) { AssertNotDisposed(); switch (origin) { case SeekOrigin.Current: if (Position + offset < 0 || Position + offset > Capacity) { throw new ArgumentOutOfRangeException(nameof(offset)); } Position += offset; _length = (int)Math.Max(Position, _length); return Position; case SeekOrigin.Begin: if (offset < 0 || offset > Capacity) { throw new ArgumentOutOfRangeException(nameof(offset)); } Position = offset; _length = (int)Math.Max(Position, _length); return Position; case SeekOrigin.End: if (Length + offset < 0) { throw new ArgumentOutOfRangeException(nameof(offset)); } if (Length + offset > Capacity) { SetCapacity((int)(Length + offset)); } Position = Length + offset; _length = (int)Math.Max(Position, _length); return Position; default: throw new ArgumentOutOfRangeException(nameof(origin)); } } /// /// 设置内容长度 /// /// /// public override void SetLength(long value) { AssertNotDisposed(); if (value < 0) { throw new ArgumentOutOfRangeException(nameof(value)); } if (value > Capacity) { SetCapacity((int)value); } _length = (int)value; if (Position > Length) { Position = Length; } } /// /// 写入到字节数组 /// /// /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public override void Write(byte[] buffer, int offset, int count) { AssertNotDisposed(); if (count == 0) { return; } if (Capacity - Position < count) { SetCapacity((int)(OverExpansionFactor * (Position + count))); } Array.Copy(buffer, offset, _data, Position, count); Position += count; _length = (int)Math.Max(Position, _length); } /// /// 写入到另一个流 /// /// /// public void WriteTo(Stream stream) { if (stream == null) { throw new ArgumentNullException(nameof(stream)); } AssertNotDisposed(); stream.Write(_data, 0, (int)Length); } /// /// 获取流的字节数组 /// /// public byte[] GetBuffer() { AssertNotDisposed(); if (_data.Length == Length) { return _data; } var buffer = new byte[Length]; Buffer.BlockCopy(_data, 0, buffer, 0, buffer.Length); return buffer; } /// /// 获取流的字节数组 /// /// public byte[] ToArray() { return GetBuffer(); } /// /// /// /// [MethodImpl(MethodImplOptions.AggressiveInlining)] protected override void Dispose(bool disposing) { if (disposing) { _isDisposed = true; Position = 0; _length = 0; if (_data != null) { _pool.Return(_data); _data = null; } } base.Dispose(disposing); } private void SetCapacity(int newCapacity) { var newData = _pool.Rent(newCapacity); if (_data != null) { Array.Copy(_data, 0, newData, 0, Position); _pool.Return(_data); } _data = newData; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void AssertNotDisposed() { if (_isDisposed) { throw new ObjectDisposedException(nameof(PooledMemoryStream)); } } /// Returns an enumerator that iterates through a collection. /// An object that can be used to iterate through the collection. IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } /// /// /// /// public IEnumerator GetEnumerator() { for (var i = 0; i < Length; i++) { yield return _data[i]; } } }