1
1

PooledMemoryStream.cs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. using System;
  2. using System.Buffers;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.Runtime.CompilerServices;
  7. namespace Masuit.Tools.Systems;
  8. /// <summary>
  9. /// 池化内存流
  10. /// </summary>
  11. public sealed class PooledMemoryStream : Stream, IEnumerable<byte>
  12. {
  13. /// <summary>
  14. /// 终结器
  15. /// </summary>
  16. ~PooledMemoryStream()
  17. {
  18. Dispose(true);
  19. }
  20. private const float OverExpansionFactor = 2;
  21. private byte[] _data = { };
  22. private int _length;
  23. private readonly ArrayPool<byte> _pool;
  24. private bool _isDisposed;
  25. public PooledMemoryStream() : this(ArrayPool<byte>.Shared)
  26. {
  27. }
  28. public PooledMemoryStream(byte[] buffer) : this(ArrayPool<byte>.Shared, buffer.Length)
  29. {
  30. Buffer.BlockCopy(buffer, 0, _data, 0, buffer.Length);
  31. _length = buffer.Length;
  32. }
  33. public PooledMemoryStream(ArrayPool<byte> arrayPool, int capacity = 0)
  34. {
  35. _pool = arrayPool ?? throw new ArgumentNullException(nameof(arrayPool));
  36. if (capacity > 0)
  37. {
  38. _data = _pool.Rent(capacity);
  39. }
  40. }
  41. public override bool CanRead => true;
  42. public override bool CanSeek => true;
  43. public override bool CanWrite => true;
  44. public override long Length => _length;
  45. public override long Position { get; set; }
  46. public long Capacity => _data?.Length ?? 0;
  47. #if NETCOREAPP || NET452
  48. public Span<byte> GetSpan()
  49. {
  50. return _data.AsSpan(0, _length);
  51. }
  52. public Memory<byte> GetMemory()
  53. {
  54. return _data.AsMemory(0, _length);
  55. }
  56. public ArraySegment<byte> ToArraySegment()
  57. {
  58. return new ArraySegment<byte>(_data, 0, (int)Length);
  59. }
  60. #endif
  61. public override void Flush()
  62. {
  63. AssertNotDisposed();
  64. }
  65. /// <summary>
  66. /// 读取到字节数组
  67. /// </summary>
  68. /// <param name="buffer"></param>
  69. /// <param name="offset"></param>
  70. /// <param name="count"></param>
  71. /// <returns></returns>
  72. public override int Read(byte[] buffer, int offset, int count)
  73. {
  74. AssertNotDisposed();
  75. if (count == 0)
  76. {
  77. return 0;
  78. }
  79. var available = Math.Min(count, Length - Position);
  80. Array.Copy(_data, Position, buffer, offset, available);
  81. Position += available;
  82. return (int)available;
  83. }
  84. /// <summary>
  85. /// 改变游标位置
  86. /// </summary>
  87. /// <param name="offset"></param>
  88. /// <param name="origin"></param>
  89. /// <returns></returns>
  90. /// <exception cref="ArgumentOutOfRangeException"></exception>
  91. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  92. public override long Seek(long offset, SeekOrigin origin)
  93. {
  94. AssertNotDisposed();
  95. switch (origin)
  96. {
  97. case SeekOrigin.Current:
  98. if (Position + offset < 0 || Position + offset > Capacity)
  99. {
  100. throw new ArgumentOutOfRangeException(nameof(offset));
  101. }
  102. Position += offset;
  103. _length = (int)Math.Max(Position, _length);
  104. return Position;
  105. case SeekOrigin.Begin:
  106. if (offset < 0 || offset > Capacity)
  107. {
  108. throw new ArgumentOutOfRangeException(nameof(offset));
  109. }
  110. Position = offset;
  111. _length = (int)Math.Max(Position, _length);
  112. return Position;
  113. case SeekOrigin.End:
  114. if (Length + offset < 0)
  115. {
  116. throw new ArgumentOutOfRangeException(nameof(offset));
  117. }
  118. if (Length + offset > Capacity)
  119. {
  120. SetCapacity((int)(Length + offset));
  121. }
  122. Position = Length + offset;
  123. _length = (int)Math.Max(Position, _length);
  124. return Position;
  125. default:
  126. throw new ArgumentOutOfRangeException(nameof(origin));
  127. }
  128. }
  129. /// <summary>
  130. /// 设置内容长度
  131. /// </summary>
  132. /// <param name="value"></param>
  133. /// <exception cref="ArgumentOutOfRangeException"></exception>
  134. public override void SetLength(long value)
  135. {
  136. AssertNotDisposed();
  137. if (value < 0)
  138. {
  139. throw new ArgumentOutOfRangeException(nameof(value));
  140. }
  141. if (value > Capacity)
  142. {
  143. SetCapacity((int)value);
  144. }
  145. _length = (int)value;
  146. if (Position > Length)
  147. {
  148. Position = Length;
  149. }
  150. }
  151. /// <summary>
  152. /// 写入到字节数组
  153. /// </summary>
  154. /// <param name="buffer"></param>
  155. /// <param name="offset"></param>
  156. /// <param name="count"></param>
  157. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  158. public override void Write(byte[] buffer, int offset, int count)
  159. {
  160. AssertNotDisposed();
  161. if (count == 0)
  162. {
  163. return;
  164. }
  165. if (Capacity - Position < count)
  166. {
  167. SetCapacity((int)(OverExpansionFactor * (Position + count)));
  168. }
  169. Array.Copy(buffer, offset, _data, Position, count);
  170. Position += count;
  171. _length = (int)Math.Max(Position, _length);
  172. }
  173. /// <summary>
  174. /// 写入到另一个流
  175. /// </summary>
  176. /// <param name="stream"></param>
  177. /// <exception cref="ArgumentNullException"></exception>
  178. public void WriteTo(Stream stream)
  179. {
  180. if (stream == null)
  181. {
  182. throw new ArgumentNullException(nameof(stream));
  183. }
  184. AssertNotDisposed();
  185. stream.Write(_data, 0, (int)Length);
  186. }
  187. /// <summary>
  188. /// 获取流的字节数组
  189. /// </summary>
  190. /// <returns></returns>
  191. public byte[] GetBuffer()
  192. {
  193. AssertNotDisposed();
  194. if (_data.Length == Length)
  195. {
  196. return _data;
  197. }
  198. var buffer = new byte[Length];
  199. Buffer.BlockCopy(_data, 0, buffer, 0, buffer.Length);
  200. return buffer;
  201. }
  202. /// <summary>
  203. /// 获取流的字节数组
  204. /// </summary>
  205. /// <returns></returns>
  206. public byte[] ToArray()
  207. {
  208. return GetBuffer();
  209. }
  210. /// <summary>
  211. ///
  212. /// </summary>
  213. /// <param name="disposing"></param>
  214. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  215. protected override void Dispose(bool disposing)
  216. {
  217. if (disposing)
  218. {
  219. _isDisposed = true;
  220. Position = 0;
  221. _length = 0;
  222. if (_data != null)
  223. {
  224. _pool.Return(_data);
  225. _data = null;
  226. }
  227. }
  228. base.Dispose(disposing);
  229. }
  230. private void SetCapacity(int newCapacity)
  231. {
  232. var newData = _pool.Rent(newCapacity);
  233. if (_data != null)
  234. {
  235. Array.Copy(_data, 0, newData, 0, Position);
  236. _pool.Return(_data);
  237. }
  238. _data = newData;
  239. }
  240. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  241. private void AssertNotDisposed()
  242. {
  243. if (_isDisposed)
  244. {
  245. throw new ObjectDisposedException(nameof(PooledMemoryStream));
  246. }
  247. }
  248. /// <summary>Returns an enumerator that iterates through a collection.</summary>
  249. /// <returns>An <see cref="T:System.Collections.IEnumerator"></see> object that can be used to iterate through the collection.</returns>
  250. IEnumerator IEnumerable.GetEnumerator()
  251. {
  252. return GetEnumerator();
  253. }
  254. /// <summary>
  255. ///
  256. /// </summary>
  257. /// <returns></returns>
  258. public IEnumerator<byte> GetEnumerator()
  259. {
  260. for (var i = 0; i < Length; i++)
  261. {
  262. yield return _data[i];
  263. }
  264. }
  265. }