In this article, we are going to learn how to convert a stream to a byte array in C#.
A Stream represents a continuous flow of data that a reader or writer can sequentially access. This access is typically byte by byte or in blocks of bytes. In C#, the Stream
class is an abstract class that provides a generic view of a sequence of bytes. To learn more about the Stream
class, please visit How to Use MemoryStream in C#.
In this article, we will explore five ways of converting a stream to a byte array. Additionally, we will perform benchmark tests to evaluate the speed and memory usage of all the methods.
Let’s dive in.
Preparation of Data Source
To begin, let’s add a text file to our project:
According to a report by ZGSMA, the mobile industry in Zootopia has seen mobile broadband connections grew from 10% in 2000 to 74% in 2023.
Now, let’s use this file to create a FileStream
object:
private static readonly string _sampleFilePath = Path.Combine(Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.FullName, "samplefile.txt"); private readonly FileStream _stream = new(_sampleFilePath, FileMode.Open, FileAccess.Read);
We aim to implement methods that convert _stream
to a byte array.
Convert Stream to Byte Array With the Stream Class
First, let’s explore how to convert a stream to a byte array using the Read()
method from the Stream
class.
The Stream.Read()
method, may not always read all the data we ask it to read. For instance, if we’re reading data from a file stream, the Read()
method may only read a section of the file and return it, even if we expect more data.
To ensure that we accurately read and convert all the data in the stream with the Stream.Read()
method, we can create a method that reads and copies the data repeatedly until there is no more data left to be read:
public byte[] UseStreamDotReadMethod(Stream stream) { byte[] bytes; List<byte> totalStream = new(); byte[] buffer = new byte[32]; int read; while ((read = stream.Read(buffer, 0, buffer.Length)) > 0) { totalStream.AddRange(buffer.Take(read)); } bytes = totalStream.ToArray(); return bytes; }
In this method, we start by initializing totalStream
, a List<byte>
object, and a buffer array of bytes with a size of 32.
Next, we define read
, an integer variable that will store the number of bytes read from the stream. Then we use a while
loop to repeatedly read data from the stream into the buffer array until no more bytes are left to read.
Inside the while loop, we check the value of the read
variable. If it is greater than zero, we add the bytes that were read to the totalStream
list using the AddRange()
method, which concatenates two lists of bytes. We use the Take()
method to select only the number of bytes read and avoid adding empty bytes to our totalStream
list.
Finally, we return the contents of the totalStream
list as a byte array using the ToArray()
method.
Convert Stream to Byte Array With the BinaryReader Class
An easier way of converting a stream to a byte array in C#, is by using the BinaryReader
class. This class allows us to read binary data from a stream and convert it into a byte array. Unlike the Stream.Read()
method, the BinaryReader.Read()
method will keep reading the data until the end of the stream once we specify the size to start with.
To see how this works, let’s create a UseBinaryReader()
method:
public byte[] UseBinaryReader(Stream stream) { byte[] bytes; using (var binaryReader = new BinaryReader(_stream)) { bytes = binaryReader.ReadBytes((int)stream.Length); } return bytes; }
Here, we instantiate a BinaryReader
object with the stream we want to read from. Next, we use the ReadBytes()
method of the BinaryReader
class to read the bytes from the stream and convert them into a byte array.
The ReadBytes()
method takes an integer parameter that specifies the number of bytes to read from the stream. In this case, we aim to read all the bytes in the stream. Therefore, we pass in the length of the stream as an argument.
Finally, we return the byte array containing the data from the stream.
Convert Stream to Byte Array With the StreamReader Class
Alternatively, we can convert a stream to a byte array with the StreamReader
class. This class allows us to easily read textual data from a stream and convert it to a byte array.
To use the StreamReader
class for this purpose, let’s define a UseStreamReader()
method:
public byte[] UseStreamReader(Stream stream) { byte[] bytes; using (var reader = new StreamReader(stream)) { bytes = System.Text.Encoding.UTF8.GetBytes(reader.ReadToEnd()); } return bytes; }
First, we create an instance of the StreamReader
class and pass in the original stream as an argument. Then, we call the ReadToEnd()
method on the reader object to read all the data from the stream as a string.
Finally, we use the GetBytes()
method of the UTF8
encoding class to convert the string to a byte array and return it to the caller.
It is important to note that this method assumes that the stream contains textual data encoded in UTF8. If the data is in a different encoding, we should use the corresponding encoding class instead of UTF8.
Convert Stream to Byte Array With the MemoryStream Class
Additionally, we can use the MemoryStream
class to convert streams to byte arrays. This class provides an efficient approach for handling memory usage during the conversion, especially when working with large data streams.
To achieve this, the MemoryStream
class buffers data in small portions. This action helps to prevent unnecessary memory allocation and reduce the memory required for the operation. As a result, this approach reduces the frequency of garbage collection, leading to an overall improvement in the process’s performance.
With this in mind, let’s define a UseMemoryStream()
method:
public byte[] UseMemoryStream(Stream stream) { byte[] bytes; if (_stream is MemoryStream memStream) { return memStream.ToArray(); } using (var memoryStream = new MemoryStream()) { stream.CopyTo(memoryStream); bytes = memoryStream.ToArray(); } return bytes; }
Here, we use an if
statement to check if the stream we want to convert is already a MemoryStream
. If it is, we call the ToArray()
method on the stream and return the resulting byte array.
However, if the stream is not a MemoryStream
, we create a new instance of the MemoryStream
class. Then, we use the CopyTo()
method to copy the contents of the original stream into the memory stream. Subsequently, we invoke the ToArray()
method on the memory stream to get the byte array representation of the stream.
Convert Stream to Byte Array With the BufferedStream Class
Now, let’s explore another method that involves using the BufferedStream
class.
The BufferedStream
class provides a way to improve the performance of a stream by incorporating a buffer.
We use a buffer to temporarily store data when transferring between components in a computer system with different speeds. This momentary storage enhances data processing and transfer efficiency by decreasing the number of calls between the system’s components. When converting a stream to a byte array, a buffer reduces the overall time for reading from the stream.
To use the BufferedStream
class to convert a stream to a byte array, let’s start by defining a method:
public byte[] UseBufferedStream(Stream stream) { byte[] bytes; using (var bufferedStream = new BufferedStream(stream)) { using var memoryStream = new MemoryStream(); bufferedStream.CopyTo(memoryStream); bytes = memoryStream.ToArray(); } return bytes; }
First and foremost, we declare a variable to hold the data we will convert. We then create an instance of the BufferedStream
class and pass in the original stream as an argument.
Next, we define a MemoryStream
object to write the data we read from the BufferedStream
object. To transfer the data between the two streams, we use the CopyTo()
method on the BufferedStream
object and pass in the MemoryStream
object as an argument.
This transfer is necessary because when working with a BufferedStream
, we store the data in a buffer, and write or read from the underlying stream only in packets, as needed. Therefore, to convert the contents of the BufferedStream
to a byte[]
array, we must first copy the buffered data to an intermediate buffer, such as a MemoryStream
, and then convert it to a byte array.
Finally, we invoke the ToArray()
method on the MemoryStream
object to retrieve the data as a byte array and return it to the caller.
What’s the Fastest Way to Convert a Stream to Byte Array in C#?
Now that all our methods are ready, we can evaluate their time and memory performance using the BenchmarkDotNet library. To view the benchmark implementation, please refer to this file//GitHub in our repository.
We can now proceed to execute our benchmark tests and examine the results on the console:
| Method | Mean | Error | StdDev | Median | Allocated | |----------------------- |------------:|---------:|---------:|------------:|-----------:| | UseBinaryReader | 393.3 us | 6.89 us | 12.77 us | 386.7 us | 746.96 KB | | UseBufferedStream | 462.4 us | 7.24 us | 5.65 us | 461.6 us | 2668.33 KB | | UseMemoryStream | 522.8 us | 19.70 us | 58.07 us | 518.1 us | 2668.27 KB | | UseStreamReader | 1,430.9 us | 22.01 us | 20.59 us | 1,428.9 us | 3756.39 KB | | UseStreamDotReadMethod | 11,117.6 us | 54.63 us | 42.65 us | 11,117.2 us | 3920.87 KB |
Based on the benchmark test results, we can see that the UseBinaryReader()
is the fastest method to convert a stream to a byte[]
array in C#. This method uses the least amount of time and memory among all the methods.
However, the UseBufferedStream()
method comes in second place, while the UseMemoryStream()
method comes in third place. These methods show similar completion time and memory usage.
Furthermore, the UseStreamReader()
method is the fourth-fastest method. This approach has the second-highest memory allocation.
Finally, the slowest method for this benchmark test is the UseStreamDotReadMethod()
method. It exhibits the slowest completion time and allocates more memory than the other methods.
Overall, we can see that the UseBinaryReader()
method is the most optimal choice to convert a stream to a byte[]
array in C#, given its low time and memory requirements.
Conclusion
In this article, we discussed five methods that we could use to convert a stream to a byte array in C#. Additionally, we performed benchmark tests to assess the speed and memory usage of all the methods.