123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310 |
- using System;
- using System.Buffers;
- using System.Collections;
- using System.Collections.Generic;
- using System.IO;
- using System.Runtime.CompilerServices;
- namespace Masuit.Tools.Systems;
- /// <summary>
- /// 池化内存流
- /// </summary>
- public sealed class PooledMemoryStream : Stream, IEnumerable<byte>
- {
- /// <summary>
- /// 终结器
- /// </summary>
- ~PooledMemoryStream()
- {
- Dispose(true);
- }
- private const float OverExpansionFactor = 2;
- private byte[] _data = { };
- private int _length;
- private readonly ArrayPool<byte> _pool;
- private bool _isDisposed;
- public PooledMemoryStream() : this(ArrayPool<byte>.Shared)
- {
- }
- public PooledMemoryStream(byte[] buffer) : this(ArrayPool<byte>.Shared, buffer.Length)
- {
- Buffer.BlockCopy(buffer, 0, _data, 0, buffer.Length);
- _length = buffer.Length;
- }
- public PooledMemoryStream(ArrayPool<byte> 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<byte> GetSpan()
- {
- return _data.AsSpan(0, _length);
- }
- public Memory<byte> GetMemory()
- {
- return _data.AsMemory(0, _length);
- }
- public ArraySegment<byte> ToArraySegment()
- {
- return new ArraySegment<byte>(_data, 0, (int)Length);
- }
- #endif
- public override void Flush()
- {
- AssertNotDisposed();
- }
- /// <summary>
- /// 读取到字节数组
- /// </summary>
- /// <param name="buffer"></param>
- /// <param name="offset"></param>
- /// <param name="count"></param>
- /// <returns></returns>
- 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;
- }
- /// <summary>
- /// 改变游标位置
- /// </summary>
- /// <param name="offset"></param>
- /// <param name="origin"></param>
- /// <returns></returns>
- /// <exception cref="ArgumentOutOfRangeException"></exception>
- [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));
- }
- }
- /// <summary>
- /// 设置内容长度
- /// </summary>
- /// <param name="value"></param>
- /// <exception cref="ArgumentOutOfRangeException"></exception>
- 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;
- }
- }
- /// <summary>
- /// 写入到字节数组
- /// </summary>
- /// <param name="buffer"></param>
- /// <param name="offset"></param>
- /// <param name="count"></param>
- [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);
- }
- /// <summary>
- /// 写入到另一个流
- /// </summary>
- /// <param name="stream"></param>
- /// <exception cref="ArgumentNullException"></exception>
- public void WriteTo(Stream stream)
- {
- if (stream == null)
- {
- throw new ArgumentNullException(nameof(stream));
- }
- AssertNotDisposed();
- stream.Write(_data, 0, (int)Length);
- }
- /// <summary>
- /// 获取流的字节数组
- /// </summary>
- /// <returns></returns>
- 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;
- }
- /// <summary>
- /// 获取流的字节数组
- /// </summary>
- /// <returns></returns>
- public byte[] ToArray()
- {
- return GetBuffer();
- }
- /// <summary>
- ///
- /// </summary>
- /// <param name="disposing"></param>
- [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));
- }
- }
- /// <summary>Returns an enumerator that iterates through a collection.</summary>
- /// <returns>An <see cref="T:System.Collections.IEnumerator"></see> object that can be used to iterate through the collection.</returns>
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
- /// <summary>
- ///
- /// </summary>
- /// <returns></returns>
- public IEnumerator<byte> GetEnumerator()
- {
- for (var i = 0; i < Length; i++)
- {
- yield return _data[i];
- }
- }
- }
|