466

Is there a simple way or method to convert a Stream into a byte[] in C#?

bubbleking
  • 3,329
  • 3
  • 29
  • 49
Pablo Fernandez
  • 279,434
  • 135
  • 377
  • 622
  • 6
    Not really the answer to the question but if your Stream comes from a file you can use `File.ReadAllBytes(path)` to get the bytes array in one line. – Jesus Jimenez Jun 18 '12 at 13:15
  • @JesusJimenez you save me a lot of time of implementation, I know than has pass a lot of time from your answer but thanks a lot – sgrysoft Jul 11 '22 at 13:14

12 Answers12

1051

The shortest solution I know:

using(var memoryStream = new MemoryStream())
{
  sourceStream.CopyTo(memoryStream);
  return memoryStream.ToArray();
}
James Dingle
  • 10,581
  • 2
  • 14
  • 4
  • 76
    Side note: CopyTo is only available with .NET Framework 4. – Simon Mourier Sep 08 '11 at 12:13
  • but does this involve two copies? – thalm Apr 13 '12 at 18:08
  • 9
    Yes it does. You could use MemoryStream.GetBuffer() to avoid the extra copy but beware that the size of the array returned is not the size of the data. – James Dingle Apr 30 '12 at 03:25
  • 4
    If the length of the source stream is known upfront, it is better to specify the capacity of the MemoryStream with this length; the internal buffer will have the proper size. If the length is not known, then writing to MemoryStream implies potential multiple copies of the internal buffer as the data is written and the buffer extended, and in that case the extra copy of ToArray is not necessarily the main problem. – James Dingle Apr 30 '12 at 03:46
  • 16
    `MemoryStream` is `IDisposable` - shouldn't it be wrapped in a `using`? – BlueRaja - Danny Pflughoeft May 27 '13 at 21:23
  • 4
    Corrected. There is no real need in the case of MemoryStream (dig in the source code, it does nothing), but this could change. – James Dingle Jul 01 '13 at 06:29
  • 1
    CopyToAsync can be used to do the call async. The method is available since .Net framework 4.5. – Valderann Aug 12 '17 at 07:53
  • Another fun note is that `memoryStream.ToArray()` is available even after the `memoryStream` is disposed. – Sam Rueby Oct 10 '19 at 19:32
  • @JamesDingle -- in this case it's probably fine if you know the size up front, since you're only using it to dump those bytes in and spit them back out -- but for general usage, avoid using the constructor parameters in memory streams -- they can have really gnarly (and unexpected) side effects (e.g. if you specify a byte array your memory stream can't grow beyond the original size). – BrainSlugs83 Nov 12 '20 at 22:46
193

Call next function like

byte[] m_Bytes = StreamHelper.ReadToEnd (mystream);

Function:

public static byte[] ReadToEnd(System.IO.Stream stream)
{
    long originalPosition = 0;

    if(stream.CanSeek)
    {
         originalPosition = stream.Position;
         stream.Position = 0;
    }

    try
    {
        byte[] readBuffer = new byte[4096];

        int totalBytesRead = 0;
        int bytesRead;

        while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
        {
            totalBytesRead += bytesRead;

            if (totalBytesRead == readBuffer.Length)
            {
                int nextByte = stream.ReadByte();
                if (nextByte != -1)
                {
                    byte[] temp = new byte[readBuffer.Length * 2];
                    Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
                    Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
                    readBuffer = temp;
                    totalBytesRead++;
                }
            }
        }

        byte[] buffer = readBuffer;
        if (readBuffer.Length != totalBytesRead)
        {
            buffer = new byte[totalBytesRead];
            Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
        }
        return buffer;
    }
    finally
    {
        if(stream.CanSeek)
        {
             stream.Position = originalPosition; 
        }
    }
}
Mark A. Donohoe
  • 28,442
  • 25
  • 137
  • 286
pedrofernandes
  • 16,354
  • 10
  • 36
  • 43
  • 22
    Not sure I'd agree with the Length*2 buffer expansion policy there. – Remus Rusanu Jul 03 '09 at 18:48
  • Yes its true. But i use this code in frameworks 1.1 and 2.0. Because this is so big. Your answer is good to. – pedrofernandes Jul 03 '09 at 18:48
  • 2
    If you want to be able to read streams of arbitrary length, pretty much all of that is needed. You could use a List and save some code.. – Thorarin Jul 03 '09 at 18:50
  • 3
    A bunch of concerns are mixed together in one big method. Yes, it all has to be done, but not all in one function. There's the growable byte array and there's the stream reading. Much easier to get right if they're separated. – Daniel Earwicker Jul 03 '09 at 18:57
  • 2
    That code could be made much simpler by using a MemoryStream... – Thomas Levesque Jul 03 '09 at 19:09
  • @Thomas - indeed, see my answer - the only custom code you need to write is a stream copy function that can then be reused for copying a stream directly to any other stream. – Daniel Earwicker Jul 03 '09 at 19:14
  • 1
    Looks like a modified version of http://www.yoda.arachsys.com/csharp/readbinary.html – SwDevMan81 Jul 06 '09 at 03:45
  • This code example doesn't consider streams that are not seekable. Setting stream.Position should only be done when stream.CanSeek is true. – Matt Z Jul 08 '10 at 08:13
75

I use this extension class:

public static class StreamExtensions
{
    public static byte[] ReadAllBytes(this Stream instream)
    {
        if (instream is MemoryStream)
            return ((MemoryStream) instream).ToArray();

        using (var memoryStream = new MemoryStream())
        {
            instream.CopyTo(memoryStream);
            return memoryStream.ToArray();
        }
    }
}

Just copy the class to your solution and you can use it on every stream:

byte[] bytes = myStream.ReadAllBytes()

Works great for all my streams and saves a lot of code! Of course you can modify this method to use some of the other approaches here to improve performance if needed, but I like to keep it simple.

JCH2k
  • 3,361
  • 32
  • 25
  • if (instream is MemoryStream) return ((MemoryStream) instream).ToArray(); Changed to: var ms = instream as MemoryStream; if (ms != null) return ms.ToArray(); – Garry Xiao Jan 06 '20 at 08:51
  • 9
    Even better with C# 7: `if (instream is MemoryStream memoryStream) return memoryStream.ToArray();` – JCH2k Jan 06 '20 at 13:53
58

In .NET Framework 4 and later, the Stream class has a built-in CopyTo method that you can use.

For earlier versions of the framework, the handy helper function to have is:

public static void CopyStream(Stream input, Stream output)
{
    byte[] b = new byte[32768];
    int r;
    while ((r = input.Read(b, 0, b.Length)) > 0)
        output.Write(b, 0, r);
}

Then use one of the above methods to copy to a MemoryStream and call GetBuffer on it:

var file = new FileStream("c:\\foo.txt", FileMode.Open);

var mem = new MemoryStream();

// If using .NET 4 or later:
file.CopyTo(mem);

// Otherwise:
CopyStream(file, mem);

// getting the internal buffer (no additional copying)
byte[] buffer = mem.GetBuffer();
long length = mem.Length; // the actual length of the data 
                          // (the array may be longer)

// if you need the array to be exactly as long as the data
byte[] truncated = mem.ToArray(); // makes another copy

Edit: originally I suggested using Jason's answer for a Stream that supports the Length property. But it had a flaw because it assumed that the Stream would return all its contents in a single Read, which is not necessarily true (not for a Socket, for example.) I don't know if there is an example of a Stream implementation in the BCL that does support Length but might return the data in shorter chunks than you request, but as anyone can inherit Stream this could easily be the case.

It's probably simpler for most cases to use the above general solution, but supposing you did want to read directly into an array that is bigEnough:

byte[] b = new byte[bigEnough];
int r, offset;
while ((r = input.Read(b, offset, b.Length - offset)) > 0)
    offset += r;

That is, repeatedly call Read and move the position you will be storing the data at.

Daniel Earwicker
  • 114,894
  • 38
  • 205
  • 284
  • Why bother with memorystream when you could just use a List and AddRange()? It's doing exactly the same anyway under the hood as far as I know. – Tamas Czinege Jul 04 '09 at 00:17
  • @DrJokepu - because stream-to-stream copying is generally useful in other situations. You only have to write that one method, and you get stream-to-stream copying and stream-to-array copying. – Daniel Earwicker Jul 04 '09 at 07:01
  • 1
    @John Saunders - that CopyStream method definitely shouldn't have using statements in it, so that would have been an odd request. The example usage might need one on the FileStream - but it might not (depends whether the rest of the code wants to reuse the same FileStream somehow). – Daniel Earwicker Jul 04 '09 at 07:04
  • As I just got an upvote on this out of the blue, I noticed it is overdue for an update as `Stream` now has a `CopyTo` method that does exactly what the `CopyStream` did. – Daniel Earwicker Feb 10 '15 at 16:41
37
Byte[] Content = new BinaryReader(file.InputStream).ReadBytes(file.ContentLength);
carlodurso
  • 2,886
  • 4
  • 24
  • 37
Tavo
  • 521
  • 5
  • 4
  • I could be wrong, but this seems to be more efficient than the MemoryStream way that creates two copies in memory. – Dan Randolph Jun 20 '16 at 20:42
  • 1
    Depends on the scenario, your example is very specific to the file stream which you can determine the content length. What about if the input is a stream? as Readbytes only accepts the int32 – Vincent Feb 20 '17 at 00:00
  • 2
    nice, but `BinaryReader` is disposable, so this should use `using`. – Nyerguds Feb 06 '19 at 09:07
30
    byte[] buf;  // byte array
    Stream stream=Page.Request.InputStream;  //initialise new stream
    buf = new byte[stream.Length];  //declare arraysize
    stream.Read(buf, 0, buf.Length); // read from stream to byte array
Sharon AS
  • 364
  • 3
  • 6
  • 5
    If I recall correctly "Read" doesn't always read the entire available amount from the stream - eg request N bytes, return M bytes with M < N. Hence the various methods to build a buffer and read a number of times. https://msdn.microsoft.com/en-us/library/system.io.stream.read(v=vs.110).aspx – David Ford Jun 30 '16 at 04:22
  • You can't be sure that you can call `Stream.Length` - it might throw an exception. – Ykok Mar 29 '23 at 12:22
8

Ok, maybe I'm missing something here, but this is the way I do it:

public static Byte[] ToByteArray(this Stream stream) {
    Int32 length = stream.Length > Int32.MaxValue ? Int32.MaxValue : Convert.ToInt32(stream.Length);
    Byte[] buffer = new Byte[length];
    stream.Read(buffer, 0, length);
    return buffer;
}
johnnyRose
  • 7,310
  • 17
  • 40
  • 61
Vinicius
  • 1,601
  • 19
  • 19
  • For this method and @user734862's method I got the following error: 'This stream does not support seek operations' a System.NotSupportedException. I think this may be down to the fact that I'm reading a file from a http location and then sending it back. It may well be different for when you are working with a file on your system. – Daniel Hollinrake Mar 01 '13 at 01:14
  • Stream.Read method can read less bytes than you request. You should check return value of Read method. – arkhivania Mar 04 '13 at 08:33
  • 1
    The stream returned from, e.g., Microsoft.SharePoint.Client.File.OpenBinaryDirect very often returns only 500 or so bytes at a time, no matter how big your buffer is. You should never ignore the return value of Stream.Read. – Dylan Nicholson Nov 15 '13 at 00:20
  • But look closely to the code. The buffer is created based on stream.Length information. It will never be too big for the stream. It may be too small (Int32.MaxValue is the maximum size for it), but this is very unlikely to happen in most cases. – Vinicius Jun 20 '14 at 05:24
  • 3
    Ths problem is that Stream.Read doesn't always read `length` bytes - it can decide to read less (and returns the actual number of bytes read). You *have* to call this in a loop to make it work universally! – JCH2k Nov 09 '17 at 16:43
7

if you post a file from mobile device or other

    byte[] fileData = null;
    using (var binaryReader = new BinaryReader(Request.Files[0].InputStream))
    {
        fileData = binaryReader.ReadBytes(Request.Files[0].ContentLength);
    }
Savas Adar
  • 4,083
  • 3
  • 46
  • 54
  • Should mention that you can actually use this on any FileStream. In WPF, you can't use `Request.Files[0].InputStream`, but you can do `using (FileStream fs = new File.OpenRead(fileName)) { var binaryReader = new BinaryReader(fs); fileData = binaryReader.ReadBytes((int)fs.Length); }`. Thanks for the tip! – vapcguy Oct 11 '16 at 23:19
5
Stream s;
int len = (int)s.Length;
byte[] b = new byte[len];
int pos = 0;
while((r = s.Read(b, pos, len - pos)) > 0) {
    pos += r;
}

A slightly more complicated solution is necesary is s.Length exceeds Int32.MaxValue. But if you need to read a stream that large into memory, you might want to think about a different approach to your problem.

Edit: If your stream does not support the Length property, modify using Earwicker's workaround.

public static class StreamExtensions {
    // Credit to Earwicker
    public static void CopyStream(this Stream input, Stream output) {
        byte[] b = new byte[32768];
        int r;
        while ((r = input.Read(b, 0, b.Length)) > 0) {
            output.Write(b, 0, r);
        }
    }
}

[...]

Stream s;
MemoryStream ms = new MemoryStream();
s.CopyStream(ms);
byte[] b = ms.GetBuffer();
Community
  • 1
  • 1
jason
  • 236,483
  • 35
  • 423
  • 525
3

You could also try just reading in parts at a time and expanding the byte array being returned:

public byte[] StreamToByteArray(string fileName)
{
    byte[] total_stream = new byte[0];
    using (Stream input = File.Open(fileName, FileMode.Open, FileAccess.Read))
    {
        byte[] stream_array = new byte[0];
        // Setup whatever read size you want (small here for testing)
        byte[] buffer = new byte[32];// * 1024];
        int read = 0;

        while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
        {
            stream_array = new byte[total_stream.Length + read];
            total_stream.CopyTo(stream_array, 0);
            Array.Copy(buffer, 0, stream_array, total_stream.Length, read);
            total_stream = stream_array;
        }
    }
    return total_stream;
}
SwDevMan81
  • 48,814
  • 22
  • 151
  • 184
3

"bigEnough" array is a bit of a stretch. Sure, buffer needs to be "big ebough" but proper design of an application should include transactions and delimiters. In this configuration each transaction would have a preset length thus your array would anticipate certain number of bytes and insert it into correctly sized buffer. Delimiters would ensure transaction integrity and would be supplied within each transaction. To make your application even better, you could use 2 channels (2 sockets). One would communicate fixed length control message transactions that would include information about size and sequence number of data transaction to be transferred using data channel. Receiver would acknowledge buffer creation and only then data would be sent. If you have no control over stream sender than you need multidimensional array as a buffer. Component arrays would be small enough to be manageable and big enough to be practical based on your estimate of expected data. Process logic would seek known start delimiters and then ending delimiter in subsequent element arrays. Once ending delimiter is found, new buffer would be created to store relevant data between delimiters and initial buffer would have to be restructured to allow data disposal.

As far as a code to convert stream into byte array is one below.

Stream s = yourStream;
int streamEnd = Convert.ToInt32(s.Length);
byte[] buffer = new byte[streamEnd];
s.Read(buffer, 0, streamEnd);
ArtK
  • 1,157
  • 5
  • 17
  • 31
  • 1
    same as every other answer: never do stream.Read() without checking the return value of how many it has actually read... – Bernhard Jul 09 '20 at 05:36
2

Quick and dirty technique:

    static byte[] StreamToByteArray(Stream inputStream)
    {
        if (!inputStream.CanRead)
        {
            throw new ArgumentException(); 
        }

        // This is optional
        if (inputStream.CanSeek)
        {
            inputStream.Seek(0, SeekOrigin.Begin);
        }

        byte[] output = new byte[inputStream.Length];
        int bytesRead = inputStream.Read(output, 0, output.Length);
        Debug.Assert(bytesRead == output.Length, "Bytes read from stream matches stream length");
        return output;
    }

Test:

    static void Main(string[] args)
    {
        byte[] data;
        string path = @"C:\Windows\System32\notepad.exe";
        using (FileStream fs = File.Open(path, FileMode.Open, FileAccess.Read))
        {
            data = StreamToByteArray(fs);
        }

        Debug.Assert(data.Length > 0);
        Debug.Assert(new FileInfo(path).Length == data.Length); 
    }

I would ask, why do you want to read a stream into a byte[], if you are wishing to copy the contents of a stream, may I suggest using MemoryStream and writing your input stream into a memory stream.

Phil Price
  • 2,283
  • 20
  • 22