How to copy one Stream to a byte array with the smallest C# code?
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();
}
}
Comments
-
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 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 almost 15 yearsdata = binaryReader.ReadBytes(stream.Length); should be data = br.ReadBytes(stream.Length);
-
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 almost 15 yearsAlthough it only works for files of course... it matches the code in the original question, but not the title of the question :)
-
Joel Coehoorn almost 15 yearsGood 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 almost 15 yearsThe 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 over 11 yearsdid anyone try this? br.ReadBytes takes an int param and stream.Length is a long. It won't compile.
-
Noldorin over 11 yearsIt'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!