From fb71df9f0b5a8457255e35cd4cd19c46396e97f1 Mon Sep 17 00:00:00 2001 From: Jon Skeet Date: Wed, 4 Jan 2017 16:40:07 +0000 Subject: Add ByteString.FromStream and ByteString.FromStreamAsync in C# Fixes #2088. We now have separate tests for netcoreapp and net45 to test the two branches here. (netstandard10 doesn't have MemoryStream.GetBuffer) Although most of this library doesn't have any async functionality, this feels like a natural place to locally add it. --- csharp/src/Google.Protobuf/ByteString.cs | 53 ++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) (limited to 'csharp/src/Google.Protobuf/ByteString.cs') diff --git a/csharp/src/Google.Protobuf/ByteString.cs b/csharp/src/Google.Protobuf/ByteString.cs index 5c652cc3..9973d211 100644 --- a/csharp/src/Google.Protobuf/ByteString.cs +++ b/csharp/src/Google.Protobuf/ByteString.cs @@ -35,6 +35,10 @@ using System.Collections; using System.Collections.Generic; using System.IO; using System.Text; +#if !DOTNET35 +using System.Threading; +using System.Threading.Tasks; +#endif namespace Google.Protobuf { @@ -141,6 +145,55 @@ namespace Google.Protobuf return bytes == "" ? Empty : new ByteString(Convert.FromBase64String(bytes)); } + /// + /// Constructs a from data in the given stream, synchronously. + /// + /// If successful, will be read completely, from the position + /// at the start of the call. + /// The stream to copy into a ByteString. + /// A ByteString with content read from the given stream. + public static ByteString FromStream(Stream stream) + { + ProtoPreconditions.CheckNotNull(stream, nameof(stream)); + int capacity = stream.CanSeek ? checked((int) (stream.Length - stream.Position)) : 0; + var memoryStream = new MemoryStream(capacity); + stream.CopyTo(memoryStream); +#if NETSTANDARD1_0 + byte[] bytes = memoryStream.ToArray(); +#else + // Avoid an extra copy if we can. + byte[] bytes = memoryStream.Length == memoryStream.Capacity ? memoryStream.GetBuffer() : memoryStream.ToArray(); +#endif + return AttachBytes(bytes); + } + +#if !DOTNET35 + /// + /// Constructs a from data in the given stream, asynchronously. + /// + /// If successful, will be read completely, from the position + /// at the start of the call. + /// The stream to copy into a ByteString. + /// The cancellation token to use when reading from the stream, if any. + /// A ByteString with content read from the given stream. + public async static Task FromStreamAsync(Stream stream, CancellationToken cancellationToken = default(CancellationToken)) + { + ProtoPreconditions.CheckNotNull(stream, nameof(stream)); + int capacity = stream.CanSeek ? checked((int) (stream.Length - stream.Position)) : 0; + var memoryStream = new MemoryStream(capacity); + // We have to specify the buffer size here, as there's no overload accepting the cancellation token + // alone. But it's documented to use 81920 by default if not specified. + await stream.CopyToAsync(memoryStream, 81920, cancellationToken); +#if NETSTANDARD1_0 + byte[] bytes = memoryStream.ToArray(); +#else + // Avoid an extra copy if we can. + byte[] bytes = memoryStream.Length == memoryStream.Capacity ? memoryStream.GetBuffer() : memoryStream.ToArray(); +#endif + return AttachBytes(bytes); + } +#endif + /// /// Constructs a from the given array. The contents /// are copied, so further modifications to the array will not -- cgit v1.2.3