Skip to content
This repository was archived by the owner on Dec 24, 2022. It is now read-only.

Commit eac56b5

Browse files
committed
Add ReadFullyAsync/ReadFullyAsMemoryAsync/CopyToAsync
1 parent 137eb1c commit eac56b5

File tree

1 file changed

+123
-0
lines changed

1 file changed

+123
-0
lines changed

src/ServiceStack.Text/StreamExtensions.cs

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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&lt;byte&gt;.
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&lt;byte&gt;.
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&lt;byte&gt;.
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

Comments
 (0)