How to copy one Stream to a byte array with the smallest C# code?

19,943

Solution 1

There's a static method that can do this for you in one call.

var data = File.ReadAllBytes(fileName);

Alternatively, a method that works for any Stream (that returns its length) would be:

byte[] data;
using (var br = new BinaryReader(stream))
    data = br.ReadBytes((int)stream.Length);

For streams that don't have a well-defined length (e.g. NetworkStream), and thus raise an exception on calling stream.Length, this of course does not work. The slightly more complicated solution presented in Jon Skeet's answer is then what you probably want.

Solution 2

How 'bout one:

byte[] result = File.ReadAllBytes(fileName);

Solution 3

Reducing your lines of code is pretty simple here (while still working with arbitrary streams, rather than just files):

using (Stream fileStream = File.OpenRead(fileName))
using (MemoryStream memoryStream = new MemoryStream())
{
    int byteRead;
    while ((byteRead = fileStream.ReadByte()) != -1)
    {
        memoryStream.WriteByte(byteRead);
    }
    return memoryStream.ToArray();
}

Obviously it's a lot more efficient to read into a buffer than to read a byte at a time, but this reduces the number of statements (as you don't need to declare both a buffer and a variable to hold the return value from Stream). Calling MemoryStream.ToArray() is simpler than reading into a newly constructed array.

Using a buffer is nicer though. Note that we really don't need BinaryReader:

using (Stream fileStream = File.OpenRead(fileName))
using (MemoryStream memoryStream = new MemoryStream())
{
    byte[] buffer = new byte[8192];
    int bytesRead;
    while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) > 0)
    {
        memoryStream.Write(buffer, 0, bytesRead);
    }
    return memoryStream.ToArray();
}

If you want to be really brutal, we could reduce the number of using statements (with either solution):

using (Stream fileStream = File.OpenRead(fileName),
              memoryStream = new MemoryStream())
{
    byte[] buffer = new byte[8192];
    int bytesRead;
    while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) > 0)
    {
        memoryStream.Write(buffer, 0, bytesRead);
    }
    return ((MemoryStream)memoryStream).ToArray();
}

But that's just nasty :)

Another option of course is to use a library such as MiscUtil which has a method to read fully from a stream :) The utility method can be as simple as this:

public static byte[] ReadFully(this Stream stream)
{
    using (MemoryStream memoryStream = new MemoryStream())
    {
        byte[] buffer = new byte[8192];
        int bytesRead;
        while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) > 0)
        {
            memoryStream.Write(buffer, 0, bytesRead);
        }
        return memoryStream.ToArray();
    }
}

Note that this never closes the stream - the caller should do that.

Solution 4

While not reducing the LOC (I'd never use this as a primary motivation), you can collapse the usings like this:

using (Stream fileStream = File.OpenRead(fileName))
using (BinaryReader binaryReader = new BinaryReader(fileStream))
using (MemoryStream memoryStream = new MemoryStream())
{
    byte[] buffer = new byte[256];
    int count;
    int totalBytes = 0;
    while ((count = binaryReader.Read(buffer, 0, 256)) > 0)
    {
        memoryStream.Write(buffer, 0, count);
        totalBytes += count;
    }
    memoryStream.Position = 0;
    byte[] transparentPng = new byte[totalBytes];
    memoryStream.Read(transparentPng, 0, totalBytes);    
}

Solution 5

Just use the CopyTo method of the Stream to copy to a MemoryStream, and get the array:

using (var fileStream = File.OpenRead(fileName))
{
    using (var memoryStream = new MemoryStream())
    {
        fileStream.CopyTo(memoryStream);
        memoryStream.Seek(0, SeekOrigin.Begin);

        byte[] transparentPng = memoryStream.ToArray();
    }
}
Share:
19,943
Jader Dias
Author by

Jader Dias

Perl, Javascript, C#, Go, Matlab and Python Developer

Updated on June 14, 2022

Comments

  • Jader Dias
    Jader Dias almost 2 years

    Until now I am counting 12 LoCs. Could you make it smaller?

    using (Stream fileStream = File.OpenRead(fileName))
    {
        using (BinaryReader binaryReader = new BinaryReader(fileStream))
        {
            using (MemoryStream memoryStream = new MemoryStream())
            {
                byte[] buffer = new byte[256];
                int count;
                int totalBytes = 0;
                while ((count = binaryReader.Read(buffer, 0, 256)) > 0)
                {
                    memoryStream.Write(buffer, 0, count);
                    totalBytes += count;
                }
                memoryStream.Position = 0;
                byte[] transparentPng = new byte[totalBytes];
                memoryStream.Read(transparentPng, 0, totalBytes);
            }
        }
    }
    
  • fretje
    fretje almost 15 years
    "why does that matter if it works?" It doesn't matter as long as you don't have to maintain the code ;-)
  • OneSHOT
    OneSHOT almost 15 years
    data = binaryReader.ReadBytes(stream.Length); should be data = br.ReadBytes(stream.Length);
  • Michael Meadows
    Michael Meadows almost 15 years
    +1 for "why does it matter..." Sometimes the most concise isn't the most readable (or the most performant). In this case, though, File.ReadAllBytes is pretty hard to beat.
  • Jon Skeet
    Jon Skeet almost 15 years
    Although it only works for files of course... it matches the code in the original question, but not the title of the question :)
  • Joel Coehoorn
    Joel Coehoorn almost 15 years
    Good point. Maybe if I get bored later I'll express this in terms of a function that accepts an open stream as input - for all the code snippets no one's bothered to put a function signature out yet.
  • Garry Shutler
    Garry Shutler almost 15 years
    The point I was trying to make (badly) is that the goal shouldn't be to reduce the LOC but to increase clarity. I'd take 30 lines of clear code over 4 lines of obfusticated madness any day.
  • BLogan
    BLogan over 11 years
    did anyone try this? br.ReadBytes takes an int param and stream.Length is a long. It won't compile.
  • Noldorin
    Noldorin over 11 years
    It's easily fixed by a simple cast though. In the case where the length of the stream is longer than the maximum Int32 value, you really don't want to be doing this anyway!