tags:

views:

2896

answers:

4

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);
        }
    }
}
+20  A: 

How 'bout one:

byte[] result = File.ReadAllBytes(fileName);
Joel Coehoorn
+1 Nicely done :)
Andrew Hare
Although it only works for files of course... it matches the code in the original question, but not the title of the question :)
Jon Skeet
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.
Joel Coehoorn
It isn't much more complicated for a stream whose length you know, as I demonstrate in my answer. For a stream of unknown length, you could probably write a 3/4 line extension method that does the job.
Noldorin
I knew there was a simpler way! Thanks, you found it for me
Jader Dias
+9  A: 

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(stream.Length);
Noldorin
Not all streams return their length though...
Jon Skeet
data = binaryReader.ReadBytes(stream.Length); should be data = br.ReadBytes(stream.Length);
OneSHOT
Yeah, cheers. Obvious typo.
Noldorin
+7  A: 

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);    
}
Garry Shutler
Nice trick, thanks.
C. Ross
Nice trick with the different using statements
Fredrik Mörk
"why does that matter if it works?" It doesn't matter as long as you don't have to maintain the code ;-)
fretje
@fretje: Precisely!
Noldorin
+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.
Michael Meadows
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.
Garry Shutler
+8  A: 

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.

Jon Skeet