1087

What is the prefered method for creating a byte array from an input stream?

Here is my current solution with .NET 3.5.

Stream s;
byte[] b;

using (BinaryReader br = new BinaryReader(s))
{
    b = br.ReadBytes((int)s.Length);
}

Is it still a better idea to read and write chunks of the stream?

huysentruitw
  • 27,376
  • 9
  • 90
  • 133
Bob
  • 97,670
  • 29
  • 122
  • 130
  • 4
    Indeed you should probably use a stream instead of a byte[]. But there are some system APIs that don't support streams. For example, you can't create a [X509Certificate2](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.x509certificates.x509certificate2.-ctor) from a stream, you have to give it a byte[] (or a string). In this case it's fine since a x509 certificate is probably not *large data*. – 0xced May 17 '19 at 08:19
  • Doesn't the Binary Reader attach a UTF-8 encoding to the stream? Won't that be a problem if you aren't reading text (like if you're reading an image, etc)? https://learn.microsoft.com/en-us/dotnet/api/system.io.binaryreader.-ctor?view=net-5.0#System_IO_BinaryReader__ctor_System_IO_Stream_ – JMarsch Jan 08 '21 at 02:15
  • @JMarsch I think, UTF-8 will only matter when you write/read strings using `BinaryWriter/Reader`. In the link you provided they write numbers and a string to a binary file. When a string is written, I believe, the length is written first, then the UTF-8 encoded string. But if you're only reading bytes, the encoding should have no effect, so to answer your question, no, this will not be an issue if you're reading an image or other "actual" binary data. – nurchi Mar 06 '23 at 17:00

19 Answers19

1455

It really depends on whether or not you can trust s.Length. For many streams, you just don't know how much data there will be. In such cases - and before .NET 4 - I'd use code like this:

public static byte[] ReadFully(Stream input)
{
    byte[] buffer = new byte[16*1024];
    using (MemoryStream ms = new MemoryStream())
    {
        int read;
        while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
        {
            ms.Write(buffer, 0, read);
        }
        return ms.ToArray();
    }
}

With .NET 4 and above, I'd use Stream.CopyTo, which is basically equivalent to the loop in my code - create the MemoryStream, call stream.CopyTo(ms) and then return ms.ToArray(). Job done.

I should perhaps explain why my answer is longer than the others. Stream.Read doesn't guarantee that it will read everything it's asked for. If you're reading from a network stream, for example, it may read one packet's worth and then return, even if there will be more data soon. BinaryReader.Read will keep going until the end of the stream or your specified size, but you still have to know the size to start with.

The above method will keep reading (and copying into a MemoryStream) until it runs out of data. It then asks the MemoryStream to return a copy of the data in an array. If you know the size to start with - or think you know the size, without being sure - you can construct the MemoryStream to be that size to start with. Likewise you can put a check at the end, and if the length of the stream is the same size as the buffer (returned by MemoryStream.GetBuffer) then you can just return the buffer. So the above code isn't quite optimised, but will at least be correct. It doesn't assume any responsibility for closing the stream - the caller should do that.

See this article for more info (and an alternative implementation).

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 11
    @Jon, it may be worth mentioning http://www.yoda.arachsys.com/csharp/readbinary.html – Sam Saffron Feb 12 '09 at 23:11
  • @Jon It seems I must set the input.Position to 0 (input.Position=0) for the read to work. Otherwise teh while loop is be ignored. Is it normally that I need to "copy/persist" the input stream and use it for later? – Jeff Mar 20 '12 at 00:41
  • 7
    @Jeff: We don't really have the context here, but if you've been writing to a stream, then yes you need to "rewind" it before reading. There's just one "cursor" saying where you are within the stream - not one for reading and a separate one for writing. – Jon Skeet Mar 20 '12 at 06:42
  • @Jon sorry if it sounds stupid but shouldn't the "rewinding" be part of ReadFully? Or is it the responsibility of the caller of this method? – Jeff Mar 21 '12 at 10:17
  • 6
    @Jeff: It's the responsibility of the caller. After all, the stream may not be seekable (e.g. a network stream) or there may simply be no need to rewind it. – Jon Skeet Mar 21 '12 at 10:19
  • 23
    Could i ask why `16*1024` specifically? – Anyname Donotcare Apr 12 '12 at 10:30
  • 6
    @just_name: I don't know if this has any significance, but (16*1024) happens to be half of Int16.MaxValue :) – caesay Apr 16 '12 at 02:18
  • 3
    @JonSkeet is there any special reason for `16*1024` ? – Royi Namir Nov 13 '12 at 07:48
  • 2
    @RoyiNamir: It's just a reasonable value in many cases, balancing throughput with memory. – Jon Skeet Nov 13 '12 at 08:06
  • 1
    @just_name The mono project also happens to use `10*1024` in their implementation. – antonijn Mar 22 '13 at 16:27
  • 1
    @Quantum: Please don't edit posts in a semantically-meaningful way like that. Your proposed change would have broken the code: `GetBuffer` can return a buffer that is larger than the actual used data. This method returns an array which is exactly the size of the data read. – Jon Skeet Jan 24 '19 at 14:15
  • In my experience, Stream.CopyTo fail with my 50MB file, it throw "Out of memory" exception. But @JonSkeet solution work. So they are not the same – chinh nguyen van Jun 11 '20 at 08:36
  • public static byte[] ReadFully(Stream input) { byte[] buffer = new byte[16*1024]; using (MemoryStream ms = new MemoryStream()) { int read; input.Seek(0, SeekOrigin.Begin); while ((read = input.Read(buffer, 0, buffer.Length)) > 0) { ms.Write(buffer, 0, read); } return ms.ToArray(); } } – gelistirici Oct 10 '21 at 23:51
  • 1
    @gelistirici: Seeking to the start of a stream that's passed in is rarely a good idea - better to let the caller do it. Overall, it's not clear what your comment was meant to achieve. – Jon Skeet Oct 11 '21 at 05:38
881

While Jon's answer is correct, he is rewriting code that already exists in CopyTo. So for .Net 4 use Sandip's solution, but for previous version of .Net use Jon's answer. Sandip's code would be improved by use of "using" as exceptions in CopyTo are, in many situations, quite likely and would leave the MemoryStream not disposed.

public static byte[] ReadFully(Stream input)
{
    using (MemoryStream ms = new MemoryStream())
    {
        input.CopyTo(ms);
        return ms.ToArray();
    }
}
Noordeen
  • 1,547
  • 20
  • 26
Nathan Phillips
  • 11,899
  • 1
  • 31
  • 24
  • 7
    What different does it make between your answer and Jon's? Also I must do this input.Position=0 for the CopyTo to work. – Jeff Mar 20 '12 at 00:42
  • 2
    @nathan , readig a file from web client (filizesize=1mb) - the iis will have to load the whole 1mb to its memory right ? – Royi Namir Nov 13 '12 at 08:14
  • 10
    @Jeff, my answer will only work on .Net 4 or above, Jons will work on lower versions by rewriting functionality provided to us in the later version. You're correct that CopyTo will only copy from the current position, if you have a Seekable stream and you want to copy from the beginning then you can move to the beginning using your code or input.Seek(0, SeekOrigin.Begin), though in many cases your stream may not be Seekable. – Nathan Phillips Feb 26 '13 at 16:20
  • @RoyiNamir, you are correct that the purpose of this code is to read the whole content of the stream into memory. I am not sure exactly what you are asking, but if you are using WebClient and this code at the client end with IIS as the server then IIS would not read the whole file into memory, but the client would. – Nathan Phillips Feb 26 '13 at 16:24
  • 5
    it might be worth checking if `input` is already a `MemorySteam` and short circuiting. I know it would be stupid of the caller to pass a `MemoryStream` but ... – Jodrell Mar 27 '13 at 12:19
  • @Jodrell agree, just like fernando-neira's answer http://stackoverflow.com/a/2630539/1037948 – drzaus Sep 21 '15 at 20:30
  • @Jodrell, doing that would only be for speed optimisation. Decisions about speed optimisation should always be taken in the context of the expected usage. If doing the check for a `MemoryStream` makes the code 1/1000 slower then it should only be done if a `MemoryStream` is likely to be passed in at least once in every thousand times, otherwise you will have an aggregate slow down. – Nathan Phillips Sep 22 '15 at 10:06
  • @NathanPhillips sounds more like a simultaneous equation to me. Shouldn't the costs of copying a `MemoryStream` to a `MemoryStream` be factored into that judgement? – Jodrell Sep 22 '15 at 11:10
  • 3
    @Jodrell, Exactly so. If you're copying millions of small streams into memory and one of them is a `MemoryStream` then whether the optimisation makes sense in your context is the comparison of the time taken to do millions of type conversions against the time taken to copy the one that's a `MemoryStream` into another `MemoryStream`. – Nathan Phillips Sep 22 '15 at 14:47
  • 2
    There is no reason to Dispose a MemoryStream; and this answer does nothing other than make the wrong criticism of another answer. – SensorSmith Oct 17 '18 at 22:50
  • It should be noted that @NathanPhillips example will copy the input `Stream` from it's current position. This could trap those assuming `CopyTo()` will copy the entire stream; it may be necessary to set `stream.Position = 0;`. [Stream.CopyTo()](https://learn.microsoft.com/en-us/dotnet/api/system.io.stream.copyto?view=netframework-4.7.2) – Aaron Jan 11 '19 at 00:56
  • NEVER create a new MemoryStream instance without guesstimate of max size. If you don't, you may internally end up unnecessarily copying around a lot of smaller arrays. – Imre Pühvel Apr 01 '20 at 08:40
133

Just want to point out that in case you have a MemoryStream you already have memorystream.ToArray() for that.

Also, if you are dealing with streams of unknown or different subtypes and you can receive a MemoryStream, you can relay on said method for those cases and still use the accepted answer for the others, like this:

public static byte[] StreamToByteArray(Stream stream)
{
    if (stream is MemoryStream)
    {
        return ((MemoryStream)stream).ToArray();                
    }
    else
    {
        // Jon Skeet's accepted answer 
        return ReadFully(stream);
    }
}
meJustAndrew
  • 6,011
  • 8
  • 50
  • 76
Fernando Neira
  • 3,944
  • 2
  • 24
  • 23
  • 1
    Huh, what are all the upvotes for? Even with the most generous assumptions, this only works for streams that are already `MemoryStream`s. Of course the example is also obviously incomplete, in how it's using an uninitialized variable. – Roman Starkov Jul 30 '10 at 23:48
  • 3
    That's right, thanks for pointing that out. The point still stands for MemoryStream though, so I fixed it to reflect that. – Fernando Neira Oct 06 '10 at 10:21
  • Just mention that for MemoryStream another possibility is MemoryStream.GetBuffer(), although there are some gotchas involved. See http://stackoverflow.com/questions/1646193/why-does-memorystream-getbuffer-always-throw and http://krishnabhargav.blogspot.dk/2009/06/net-funda-memorystream-toarray-vs.html – RenniePet Jan 02 '13 at 05:29
  • 5
    This actually introduces a bug into Skeet's code; If you call `stream.Seek(1L, SeekOrigin.Begin)`, before you invoke readfully, if the stream is a memory stream you will get 1 more byte than if it is any other stream. If the caller expects to read from where the current position is to the end of the stream then you must not use `CopyTo` or `ToArray()`; In most cases this will not be an issue, but if the caller doesn't know about this quirky behavior they will be confused. – leat Aug 07 '15 at 08:26
76
MemoryStream ms = new MemoryStream();
file.PostedFile.InputStream.CopyTo(ms);
var byts = ms.ToArray();
ms.Dispose();
Sandip Patel
  • 777
  • 5
  • 2
  • 15
    MemoryStream should be created with "new MemoryStream(file.PostedFile.ContentLength)" to avoid memory fragmentation. – Dan Randolph Jun 20 '16 at 20:04
57

just my couple cents... the practice that I often use is to organize the methods like this as a custom helper

public static class StreamHelpers
{
    public static byte[] ReadFully(this Stream input)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            input.CopyTo(ms);
            return ms.ToArray();
        }
    }
}

add namespace to the config file and use it anywhere you wish

Mr. Pumpkin
  • 6,212
  • 6
  • 44
  • 60
  • 7
    Note that this will not work in .NET 3.5 and below as `CopyTo` wasn't available on `Stream` until 4.0. – Tim Oct 14 '14 at 18:31
21

You can simply use ToArray() method of MemoryStream class, for ex-

MemoryStream ms = (MemoryStream)dataInStream;
byte[] imageBytes = ms.ToArray();
Nilesh Kumar
  • 287
  • 2
  • 4
  • 4
    this will only work if `dataInStream` is already a `MemoryStream` – Fowl Aug 03 '21 at 05:23
  • @Fowl you can do *dataInStream.CopyTo(ms);* Make sure to first do *MemoryStream ms = MemoryStream();* before you attempt to copy your *dataInStream* to *ms*. – Joseph Oct 04 '22 at 12:01
14

You can even make it fancier with extensions:

namespace Foo
{
    public static class Extensions
    {
        public static byte[] ToByteArray(this Stream stream)
        {
            using (stream)
            {
                using (MemoryStream memStream = new MemoryStream())
                {
                     stream.CopyTo(memStream);
                     return memStream.ToArray();
                }
            }
        }
    }
}

And then call it as a regular method:

byte[] arr = someStream.ToByteArray()
Michal T
  • 814
  • 8
  • 5
  • 79
    I think it's a bad idea to put the input stream in a using block. That responsibility should rest with the calling procedure. – Jeff Aug 22 '13 at 19:33
8

Combinig two of the most up-voted answers into an extension method:

public static byte[] ToByteArray(this Stream stream)
{
    if (stream is MemoryStream)
        return ((MemoryStream)stream).ToArray();
    else
    {
        using MemoryStream ms = new();
        stream.CopyTo(ms);
        return ms.ToArray();
    }            
}
Mikael Dúi Bolinder
  • 2,080
  • 2
  • 19
  • 44
önder çalbay
  • 143
  • 1
  • 3
8

In case anyone likes it, here is a .NET 4+ only solution formed as an extension method without the needless Dispose call on the MemoryStream. This is a hopelessly trivial optimization, but it is worth noting that failing to Dispose a MemoryStream is not a real failure.

public static class StreamHelpers
{
    public static byte[] ReadFully(this Stream input)
    {
        var ms = new MemoryStream();
        input.CopyTo(ms);
        return ms.ToArray();
    }
}
SensorSmith
  • 1,129
  • 1
  • 12
  • 25
8

I get a compile time error with Bob's (i.e. the questioner's) code. Stream.Length is a long whereas BinaryReader.ReadBytes takes an integer parameter. In my case, I do not expect to be dealing with Streams large enough to require long precision, so I use the following:

Stream s;
byte[] b;

if (s.Length > int.MaxValue) {
  throw new Exception("This stream is larger than the conversion algorithm can currently handle.");
}

using (var br = new BinaryReader(s)) {
  b = br.ReadBytes((int)s.Length);
}
Brian Hinchey
  • 3,601
  • 1
  • 39
  • 36
5

The one above is ok...but you will encounter data corruption when you send stuff over SMTP (if you need to). I've altered to something else that will help to correctly send byte for byte: '

using System;
using System.IO;

        private static byte[] ReadFully(string input)
        {
            FileStream sourceFile = new FileStream(input, FileMode.Open); //Open streamer
            BinaryReader binReader = new BinaryReader(sourceFile);
            byte[] output = new byte[sourceFile.Length]; //create byte array of size file
            for (long i = 0; i < sourceFile.Length; i++)
                output[i] = binReader.ReadByte(); //read until done
            sourceFile.Close(); //dispose streamer
            binReader.Close(); //dispose reader
            return output;
        }'
NothinRandom
  • 225
  • 1
  • 4
  • 12
  • I don't see where this code avoids data corruption. Can you explain it? – Nippey Oct 11 '12 at 07:38
  • Let's say that you have a picture and you want to send it via SMTP. You'll probably use base64 encoding. For some reason, the file gets corrupted if you break it up as bytes. However, using a binary reader will allow the file to be successfully sent. – NothinRandom Oct 29 '12 at 23:36
  • 3
    Somewhat old, but I felt this bears mentioning - the implementation @NothinRandom provides works with strings, not streams. It would probably be simplest to just use File.ReadAllBytes in this case, though. – XwipeoutX Apr 11 '14 at 06:35
  • 1
    Downvote because of dangerous code style (no automatic Dispose/using). – arni Dec 01 '17 at 17:10
  • Sadly only -1 allowed, nothing to do with the question, file name parameter named input, not disposing, no reading buffer, no filemode, and binary reader to read byte by byte why? – Aridane Álamo May 07 '20 at 18:54
4

Create a helper class and reference it anywhere you wish to use it.

public static class StreamHelpers
{
    public static byte[] ReadFully(this Stream input)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            input.CopyTo(ms);
            return ms.ToArray();
        }
    }
}
Draken
  • 3,134
  • 13
  • 34
  • 54
4

In namespace RestSharp.Extensions there is method ReadAsBytes. Inside this method is used MemoryStream and there is the same code like in some examples on this page but when you are using RestSharp this is easiest way.

using RestSharp.Extensions;
var byteArray = inputStream.ReadAsBytes();
4

If a stream supports the Length property, a byte array can be directly created. The advantage is that MemoryStream.ToArray creates the array twice. Plus, probably some unused extra bytes in the buffer. This solution allocates the exact array needed. If the stream does not support the Length property, it will throw NotSupportedException exception.

It is also worth noting that arrays cannot be bigger than int.MaxValue.

public static async Task<byte[]> ToArrayAsync(this Stream stream)
{
    var array = new byte[stream.Length];
    await stream.ReadAsync(array, 0, (int)stream.Length);
    return array;
}

Complete code which switches between both versions based on whether the stream supports seeking or not. It includes checks for Position and unreliable Length. That might slightly reduce speed. In my tests ToArrayAsyncDirect is about 3 times faster compared to ToArrayAsyncGeneral.

public static class StreamExtensions
{
    public static readonly byte[] TempArray = new byte[4];

    /// <summary>
    /// Converts stream to byte array.
    /// </summary>
    /// <param name="stream">Stream</param>
    /// <param name="cancellationToken">Cancellation token</param>
    /// <returns>Stream data as array</returns>
    /// <returns>Binary data from stream in an array</returns>
    public static async Task<byte[]> ToArrayAsync(this Stream stream, CancellationToken cancellationToken)
    {
        if (!stream.CanRead)
        {
            throw new AccessViolationException("Stream cannot be read");
        }

        if (stream.CanSeek)
        {
            return await ToArrayAsyncDirect(stream, cancellationToken);
        }
        else
        {
            return await ToArrayAsyncGeneral(stream, cancellationToken);
        }
    }

    /// <summary>
    /// Converts stream to byte array through MemoryStream. This doubles allocations compared to ToArrayAsyncDirect.
    /// </summary>
    /// <param name="stream">Stream</param>
    /// <param name="cancellationToken">Cancellation token</param>
    /// <returns></returns>
    private static async Task<byte[]> ToArrayAsyncGeneral(Stream stream, CancellationToken cancellationToken)
    {
        using MemoryStream memoryStream = new MemoryStream();
        await stream.CopyToAsync(memoryStream, cancellationToken);
        return memoryStream.ToArray();
    }

    /// <summary>
    /// Converts stream to byte array without unnecessary allocations.
    /// </summary>
    /// <param name="stream">Stream</param>
    /// <param name="cancellationToken">Cancellation token</param>
    /// <returns>Stream data as array</returns>
    /// <exception cref="ArgumentException">Thrown if stream is not providing correct Length</exception>
    private static async Task<byte[]> ToArrayAsyncDirect(Stream stream, CancellationToken cancellationToken)
    {
        if (stream.Position > 0)
        {
            throw new ArgumentException("Stream is not at the start!");
        }


        var array = new byte[stream.Length];
        int bytesRead = await stream.ReadAsync(array, 0, (int)stream.Length, cancellationToken);

        if (bytesRead != array.Length ||
            await stream.ReadAsync(TempArray, 0, TempArray.Length, cancellationToken) > 0)
        {
            throw new ArgumentException("Stream does not have reliable Length!");
        }

        return array;
    }
}
adsamcik
  • 1,265
  • 12
  • 14
  • Firstly, sometime a stream supports `Length` but it's unreliable (example: S3 streams from AWS). Secondly - you might want to `Seek(0 ,0)` before reading. Overall: this is a good but dangerous answer :) – Alex from Jitbit Nov 16 '22 at 14:26
  • In case of S3 streams from AWS, I think `CanSeek` would be false so it would not use Length anyway, but if you can provide what Stream class they use I can look into it. `Seek(0 ,0)` is definitely a good idea, but it can only be used in the direct method so it would create inconsistent behaviour in my opinion. I have updated my answer to include additional checks to address the concerns. – adsamcik Jan 26 '23 at 09:08
3

This is the function which I am using, tested and worked well. please bear in mind that 'input' should not be null and 'input.position' should reset to '0' before reading otherwise it will break the read loop and nothing will read to convert to array.

    public static byte[] StreamToByteArray(Stream input)
    {
        if (input == null)
            return null;
        byte[] buffer = new byte[16 * 1024];
        input.Position = 0;
        using (MemoryStream ms = new MemoryStream())
        {
            int read;
            while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
            {
                ms.Write(buffer, 0, read);
            }
            byte[] temp = ms.ToArray();

            return temp;
        }
    }
Fred.S
  • 64
  • 2
2

You can use this extension method.

public static class StreamExtensions
{
    public static byte[] ToByteArray(this Stream stream)
    {
        var bytes = new List<byte>();

        int b;

        // -1 is a special value that mark the end of the stream
        while ((b = stream.ReadByte()) != -1)
            bytes.Add((byte)b);

        return bytes.ToArray();
    }
}
Orace
  • 7,822
  • 30
  • 45
Egemen Çiftci
  • 699
  • 5
  • 13
2

Since there's no modern (i.e. async) version of this answer, this is the extension method I use for this purpose:

public static async Task<byte[]> ReadAsByteArrayAsync(this Stream source)
{
    // Optimization
    if (source is MemoryStream memorySource)
        return memorySource.ToArray();

    using var memoryStream = new MemoryStream();
    await source.CopyToAsync(memoryStream);
    return memoryStream.ToArray();
}

The optimization is based on the fact the source code for ToArray calls some internal methods.

Kirk Woll
  • 76,112
  • 22
  • 180
  • 195
0
MemoryStream stream = new MemoryStream();
// do what you want to save in stream buffer
//  ...
// then define byte array with specific size same as stream length.
byte[] readByte = new byte[stream.Length];
// copy all byte from stream to an byte array
readByte = stream.ToArray();
-7

i was able to make it work on a single line:

byte [] byteArr= ((MemoryStream)localStream).ToArray();

as clarified by johnnyRose, Above code will only work for MemoryStream

Community
  • 1
  • 1
Abba
  • 519
  • 6
  • 17
  • 2
    What if `localStream` isn't a `MemoryStream`? This code will fail. – johnnyRose Mar 17 '17 at 15:35
  • localStream has to be a stream based object. more about stream based object here http://stackoverflow.com/questions/8156896/difference-between-memory-stream-and-filestream – Abba Mar 17 '17 at 20:48
  • 1
    What I was trying to suggest is, if you try to cast `localStream` to a `MemoryStream`, but `localStream` is **not** a `MemoryStream`, it _will_ fail. This code will compile fine, but it could fail at runtime, depending on the actual type of `localStream`. You can't always arbitrarily cast a base type to a child type; [read more here](http://stackoverflow.com/a/4453259/2840103). [This is another good example](http://stackoverflow.com/a/729532/2840103) which explains _why_ you can't always do this. – johnnyRose Mar 17 '17 at 21:01
  • To elaborate on my above comment: all MemoryStreams are Streams, but not all Streams are MemoryStreams. – johnnyRose Mar 17 '17 at 21:05
  • all Stream based object have Stream as base type. And Stream itself can always be convertible to memory stream. No matter what stream based object you try to cast to Meomry Stream, it should always work. Our goal here is to convert stream object to bytes array. Can you give me a signle case where It will fail? – Abba Mar 20 '17 at 17:38
  • 1
    That is just wrong. Simple example: a `FileStream` can't be casted to a `MemoryStream`, and will fail with this error: "Unable to cast object of type 'System.IO.FileStream' to type 'System.IO.MemoryStream'." Example: `using (Stream fs = new FileStream(@"C:\pathtofile.txt", FileMode.Open)) { var memoryStream = (MemoryStream)fs; }` This won't compile if you simply use `var`, because it will implicitly type to a `MemoryStream`. Typing it with `Stream` as above creates a runtime exception as I explained previously. Try it and see for yourself. – johnnyRose Mar 20 '17 at 18:42
  • If you have more questions, we should probably move this conversation to chat. Otherwise, try my code and you will see. The examples here using `CopyTo` are correct - the code in your answer will only work if `(localStream is MemoryStream) == true`, as stated previously. – johnnyRose Mar 20 '17 at 18:47
  • now, i get your point, `CopyTo` is the way to go. Thanks for clarifications – Abba Mar 20 '17 at 21:26