@@ -112,6 +112,62 @@ public static byte[] ReadFully(this Stream input, byte[] buffer)
112112 return tempStream . ToArray ( ) ;
113113 }
114114
115+ /// <summary>
116+ /// Reads the given stream up to the end, returning the data as a byte array.
117+ /// </summary>
118+ public static Task < byte [ ] > ReadFullyAsync ( this Stream input , CancellationToken token = default ) =>
119+ ReadFullyAsync ( input , DefaultBufferSize , token ) ;
120+
121+ /// <summary>
122+ /// Reads the given stream up to the end, returning the data as a byte
123+ /// array, using the given buffer size.
124+ /// </summary>
125+ public static async Task < byte [ ] > ReadFullyAsync ( this Stream input , int bufferSize , CancellationToken token = default )
126+ {
127+ if ( bufferSize < 1 )
128+ throw new ArgumentOutOfRangeException ( nameof ( bufferSize ) ) ;
129+
130+ byte [ ] buffer = BufferPool . GetBuffer ( bufferSize ) ;
131+ try
132+ {
133+ return await ReadFullyAsync ( input , buffer , token ) ;
134+ }
135+ finally
136+ {
137+ BufferPool . ReleaseBufferToPool ( ref buffer ) ;
138+ }
139+ }
140+
141+ /// <summary>
142+ /// Reads the given stream up to the end, returning the data as a byte
143+ /// array, using the given buffer for transferring data. Note that the
144+ /// current contents of the buffer is ignored, so the buffer needn't
145+ /// be cleared beforehand.
146+ /// </summary>
147+ public static async Task < byte [ ] > ReadFullyAsync ( this Stream input , byte [ ] buffer , CancellationToken token = default )
148+ {
149+ if ( buffer == null )
150+ throw new ArgumentNullException ( nameof ( buffer ) ) ;
151+
152+ if ( input == null )
153+ throw new ArgumentNullException ( nameof ( input ) ) ;
154+
155+ if ( buffer . Length == 0 )
156+ throw new ArgumentException ( "Buffer has length of 0" ) ;
157+
158+ // We could do all our own work here, but using MemoryStream is easier
159+ // and likely to be just as efficient.
160+ using var tempStream = MemoryStreamFactory . GetStream ( ) ;
161+ await CopyToAsync ( input , tempStream , buffer , token ) ;
162+ // No need to copy the buffer if it's the right size
163+ if ( tempStream . Length == tempStream . GetBuffer ( ) . Length )
164+ {
165+ return tempStream . GetBuffer ( ) ;
166+ }
167+ // Okay, make a copy that's the right size
168+ return tempStream . ToArray ( ) ;
169+ }
170+
115171 /// <summary>
116172 /// Reads the given stream up to the end, returning the MemoryStream Buffer as ReadOnlyMemory<byte>.
117173 /// </summary>
@@ -150,6 +206,44 @@ public static ReadOnlyMemory<byte> ReadFullyAsMemory(this Stream input, byte[] b
150206 return ms . GetBufferAsMemory ( ) ;
151207 }
152208
209+ /// <summary>
210+ /// Reads the given stream up to the end, returning the MemoryStream Buffer as ReadOnlyMemory<byte>.
211+ /// </summary>
212+ public static Task < ReadOnlyMemory < byte > > ReadFullyAsMemoryAsync ( this Stream input , CancellationToken token = default ) =>
213+ ReadFullyAsMemoryAsync ( input , DefaultBufferSize , token ) ;
214+
215+ /// <summary>
216+ /// Reads the given stream up to the end, returning the MemoryStream Buffer as ReadOnlyMemory<byte>.
217+ /// </summary>
218+ public static async Task < ReadOnlyMemory < byte > > ReadFullyAsMemoryAsync ( this Stream input , int bufferSize , CancellationToken token = default )
219+ {
220+ byte [ ] buffer = BufferPool . GetBuffer ( bufferSize ) ;
221+ try
222+ {
223+ return await ReadFullyAsMemoryAsync ( input , buffer , token ) ;
224+ }
225+ finally
226+ {
227+ BufferPool . ReleaseBufferToPool ( ref buffer ) ;
228+ }
229+ }
230+
231+ public static async Task < ReadOnlyMemory < byte > > ReadFullyAsMemoryAsync ( this Stream input , byte [ ] buffer , CancellationToken token = default )
232+ {
233+ if ( buffer == null )
234+ throw new ArgumentNullException ( nameof ( buffer ) ) ;
235+
236+ if ( input == null )
237+ throw new ArgumentNullException ( nameof ( input ) ) ;
238+
239+ if ( buffer . Length == 0 )
240+ throw new ArgumentException ( "Buffer has length of 0" ) ;
241+
242+ var ms = new MemoryStream ( ) ;
243+ await CopyToAsync ( input , ms , buffer , token ) ;
244+ return ms . GetBufferAsMemory ( ) ;
245+ }
246+
153247
154248 /// <summary>
155249 /// Copies all the data from one stream into another.
@@ -200,6 +294,35 @@ public static long CopyTo(this Stream input, Stream output, byte[] buffer)
200294 return total ;
201295 }
202296
297+ /// <summary>
298+ /// Copies all the data from one stream into another, using the given
299+ /// buffer for transferring data. Note that the current contents of
300+ /// the buffer is ignored, so the buffer needn't be cleared beforehand.
301+ /// </summary>
302+ public static async Task < long > CopyToAsync ( this Stream input , Stream output , byte [ ] buffer , CancellationToken token = default )
303+ {
304+ if ( buffer == null )
305+ throw new ArgumentNullException ( nameof ( buffer ) ) ;
306+
307+ if ( input == null )
308+ throw new ArgumentNullException ( nameof ( input ) ) ;
309+
310+ if ( output == null )
311+ throw new ArgumentNullException ( nameof ( output ) ) ;
312+
313+ if ( buffer . Length == 0 )
314+ throw new ArgumentException ( "Buffer has length of 0" ) ;
315+
316+ long total = 0 ;
317+ int read ;
318+ while ( ( read = await input . ReadAsync ( buffer , 0 , buffer . Length , token ) ) > 0 )
319+ {
320+ await output . WriteAsync ( buffer , 0 , read , token ) ;
321+ total += read ;
322+ }
323+ return total ;
324+ }
325+
203326 /// <summary>
204327 /// Reads exactly the given number of bytes from the specified stream.
205328 /// If the end of the stream is reached before the specified amount
0 commit comments