56

I am getting the result StreamReader object.

I want to convert the result into byte[].

How can I convert StreamReaderto byte[]?

Thanks

SharpC
  • 6,974
  • 4
  • 45
  • 40
usr021986
  • 3,421
  • 14
  • 53
  • 64

7 Answers7

73

Just throw everything you read into a MemoryStream and get the byte array in the end. As noted, you should be reading from the underlying stream to get the raw bytes.

var bytes = default(byte[]);
using (var memstream = new MemoryStream())
{
    var buffer = new byte[512];
    var bytesRead = default(int);
    while ((bytesRead = reader.BaseStream.Read(buffer, 0, buffer.Length)) > 0)
        memstream.Write(buffer, 0, bytesRead);
    bytes = memstream.ToArray();
}

Or if you don't want to manage the buffers:

var bytes = default(byte[]);
using (var memstream = new MemoryStream())
{
    reader.BaseStream.CopyTo(memstream);
    bytes = memstream.ToArray();
}
Jeff Mercado
  • 129,526
  • 32
  • 251
  • 272
  • Eh... Why the detour with the MemoryStream? – Daniel Hilgarth May 03 '11 at 09:09
  • @Daniel: Well, unless you know the length of the stream beforehand you're going to have to read it into some kind of variable length thing. I guess MemoryStream is one choice. @Jeff: What's with the use of `default()`? I don't think it makes things any more readable. – Matti Virkkunen May 03 '11 at 09:13
  • @Daniel: I'm not sure what you mean by "detour," but as far as I can tell, the asker wants to create a byte array of the entire contents of the stream, not just part of it. Using a `MemoryStream` will manage the size for us as we read in the data. – Jeff Mercado May 03 '11 at 09:14
  • @Jeff: It just seems strange to use a `MemoryStream` for this when a simple `List` in conjunction with `AddRange` would suffice. It won't change the code much, but it just *feels weird* to me to use a memory stream here :-) – Daniel Hilgarth May 03 '11 at 09:16
  • 3
    @Matti: It's just a coding style I picked up, I am embracing the `var` keyword whenever I can (for most local variables). I don't expect everyone to be comfortable with it but I'm ok with that. – Jeff Mercado May 03 '11 at 09:16
  • @Daniel: A `MemoryStream` is just a wrapper to a `byte[]`. A `List` is just a wrapper to a `T[]`. It is much more appropriate to me, especially since we're already dealing with streams. – Jeff Mercado May 03 '11 at 09:18
  • 1
    @Daniel: A `MemoryStream` is likely to be slightly more efficient as it's designed to efficiently handle arrays of bytes. For instance, you can add only a part of an array with `Write` (unlike with `AddRange` on a `List`), and it doesn't access byte arrays via an interface, which might be slightly less efficient. You can also get the underlying array directly with `GetBuffer()` without creating a copy of it. Of course, this is only important if you have a big amount of data. – Matti Virkkunen May 03 '11 at 09:22
  • @Jeff: I... really don't see the point of your weird `var`...`default` thing. It's making the code less readable *and* longer. Where exactly did you pick this up...? – Matti Virkkunen May 03 '11 at 09:23
  • @Matti: Just so you know, `GetBuffer()` will return the underlying byte array only if it was passed in to the constructor (the array the `MemoryStream` is wrapping). Otherwise, you'd have to use `ToArray()`. As for the `var` stuff, a lot of the code I deal with (particularly in other languages) use implicit typing and it's just a preference of mine to use it for local variables with exceptions for delegates/lambdas. It's kinda hard to explain so I'll just leave it at that. :) – Jeff Mercado May 03 '11 at 09:31
  • @Jeff: Actually, you can access the buffer even if you didn't pass in an array to the constructor. It will have extraneous data in it, though, so I guess it's only useful if you really really want to avoid allocations. But if you have that much data, you probably wouldn't want to read it all into memory at once anyways... – Matti Virkkunen May 03 '11 at 09:44
  • @Matti: Ah, I could have sworn that `GetBuffer()` would have thrown in this case. It appears it only does only in some select cases. – Jeff Mercado May 03 '11 at 09:49
  • @Jeff: The documentation *is* indeed a bit vague as to what a "a publicly visible buffer" is. – Matti Virkkunen May 03 '11 at 09:51
46

A StreamReader is for text, not plain bytes. Don't use a StreamReader, and instead read directly from the underlying stream.

Matti Virkkunen
  • 63,558
  • 9
  • 127
  • 159
3

You can also use CopyTo:

var ms = new MemoryStream();
yourStreamReader.BaseStream.CopyTo(ms); // blocking call till the end of the stream
ms.GetBuffer().CopyTo(yourArray, ms.Length);

or

var ms = new MemoryStream();
var ct = yourStreamReader.BaseStream.CopyToAsync(ms);
await ct;
ms.GetBuffer().CopyTo(yourArray, ms.Length);
Mikl X
  • 1,199
  • 11
  • 17
1
        BlobClient blob = container.GetBlobClient(path);
        //blob.DownloadTo(@"temp\"+ file);
        var response = blob.DownloadContent();
        var stream = response.Value.Content.ToStream();
        using (var sr = new StreamReader(stream))
        {
            using (MemoryStream ms = new MemoryStream())
            {
                sr.BaseStream.CopyTo(ms);
                return Convert.ToBase64String(ms.ToArray()) ;
            }
        }
Jun Liu
  • 11
  • 1
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Oct 08 '21 at 07:21
1

As Matti Virkkunen pointed out, you don't neccessarily need the MemoryStream. When the stream is not too long you can write into an array directly. Less allocated memory is the advantage.

using (var stream = File.OpenRead("your_file.ext"))
{
    var length = stream.Length;
    if (length <= int.MaxValue)
    {
        var result = new byte[length];
        var bytesRead = stream.Read(result, 0, (int)length);
        if (bytesRead == length) return result;
    }
    //fallback
    using (var memoryStream = new MemoryStream())
    {
        stream.CopyTo(memoryStream);
        return memoryStream.ToArray();
    }
}
Manuel
  • 157
  • 1
  • 10
-2

You can use this code: You shouldn't use this code:

byte[] bytes = streamReader.CurrentEncoding.GetBytes(streamReader.ReadToEnd());

Please see the comment to this answer as to why. I will leave the answer, so people know about the problems with this approach, because I didn't up till now.

Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • 14
    **This is wrong.** (So stop upvoting it!) This first converts bytes to text and then back to bytes. Apart from the fact that the mapping is inefficient, it may also be non-isomorphic (for instance, not every byte sequence is a valid character sequence in every encoding). Consequently, this may destroy the byte sequence, or result in an error. This is **not** an appropriate way of reading bytes. – Konrad Rudolph May 03 '11 at 09:00
  • 9
    (By the way, the updated answer is fine as an FYI so there’s no need to *downvote* it either …) – Konrad Rudolph May 03 '11 at 09:10
  • 1
    @KonradRudolph if we responded to every question with answers of what _not_ to do it would become a mess very quickly, since every question could have thousands of such valid answers. For that reason, I don't see value in having an answer being just "don't do this particular thing". – julealgon Dec 24 '20 at 14:49
  • @julealgon Yes, I now agree. – Konrad Rudolph Dec 24 '20 at 18:12
-5

For everyone saying to get the bytes, copy it to MemoryStream, etc. - if the content isn't expected to be larger than computer's memory should be reasonably be expected to allow, why not just use StreamReader's built in ReadLine() or ReadToEnd()? I saw these weren't even mentioned, and they do everything for you.

I had a use-case where I just wanted to store the path of a SQLite file from a FileDialogResult that the user picks during the synching/initialization process. My program then later needs to use this path when it is run for normal application processes. Maybe not the ideal way to capture/re-use the information, but it's not much different than writing to/reading from an .ini file - I just didn't want to set one up for one value. So I just read it from a flat, one-line text file. Here's what I did:

string filePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
if (!filePath.EndsWith(@"\")) temppath += @"\"; // ensures we have a slash on the end
filePath = filePath.Replace(@"\\", @"\"); // Visual Studio escapes slashes by putting double-slashes in their results - this ensures we don't have double-slashes
filePath += "SQLite.txt";

string path = String.Empty;
FileStream fs = new FileStream(filePath, FileMode.Open);
StreamReader sr = new StreamReader(fs);
path = sr.ReadLine();  // can also use sr.ReadToEnd();
sr.Close();
fs.Close();
fs.Flush();

return path;

If you REALLY need a byte[] instead of a string for some reason, using my example, you can always do:

byte[] toBytes;
FileStream fs = new FileStream(filePath, FileMode.Open);
StreamReader sr = new StreamReader(fs);
toBytes = Encoding.ASCII.GetBytes(path);
sr.Close();
fs.Close();
fs.Flush();

return toBytes;

(Returning toBytes instead of path.)

If you don't want ASCII you can easily replace that with UTF8, Unicode, etc.

vapcguy
  • 7,097
  • 1
  • 56
  • 52
  • 1
    answer unrelated to the question – Mike Keskinov Jun 10 '17 at 16:38
  • @MikeKeskinov Really? Did you even read my answer fully? Do you know how to read code? The OP wanted to convert a Stream to bytes. This answer shows how to take a file, read it into a Stream, then read the text into `path`, a string variable (because why would you ever need bytes when you want to read text from a file?!). But I also included how to convert that string to bytes, if bytes were truly needed. – vapcguy Jun 13 '17 at 15:25
  • The original question didn't mention reading *text*. It could be a binary file that is being read. You mention using `Encoding.ASCII.GetBytes(...)`, but a quick look at the documentation for that shows it mentioning 7-bit, so the input may well get mangled. Similarly, UTF-8 encoding makes assumptions about the input that also don't hold when fed with arbitrary binary files. – xyz Jan 03 '18 at 13:21
  • @xyz You're correct, but that's up to the developer to know what their input is and adjust the Encoding for it, in the first place-kinda a given. The OP on this question didn't give a lot of information on where the data was being read from or its format, so to build an answer, I had to make an assumption it was text in a text file, and even (*as a bonus!*) included that bit about getting bytes. If it's bytes, there's of course more than just `Encoding.ASCII.GetBytes()`, but `Encoding.UTF8.GetBytes()`, `Encoding.Unicode.GetBytes()`, etc. Use the intellisense before just ragging on an answer. – vapcguy Feb 09 '18 at 17:47
  • @vapcguy This code _can_ work depending on context. Other solutions _will always work_ regardless of context. I didn't downvote you, but I can understand why people would prefer a solution that _always_ works vs a solution that _sometimes_ works. – mjwills Dec 16 '21 at 06:43
  • @mjwills The only time it won't is if you have a file that exceeds the memory (RAM) of your system, so it will work in 99.9% of the cases. I find it hard to believe a programmer will have a file like that on the daily, but if they do, they can create a buffer system, instead, like in the accepted answer. I didn't want to repeat what was already offered. – vapcguy Jan 03 '22 at 18:51
  • You can't treat binary files as text files and say it will work 99.9% of the time. It will work 99.9% of the time for specific file types, yes. Which, by definition, is less appropriate than using a technique which will _always_ work. As per my previous comment. – mjwills Jan 04 '22 at 22:44
  • @mjwills When can't you treat a binary file as text? Isn't it just 0s and 1s? – vapcguy Jan 06 '22 at 09:52
  • http://haacked.com/archive/2012/01/30/hazards-of-converting-binary-data-to-a-string.aspx/ is one example of why treating binary files as string does not always work as you might hope @vapcguy – mjwills Jan 07 '22 at 10:16
  • @mjwills Not a bad point, but the link you cited uses `UTF-8`, whereas I have it using `ASCII` & that was only if they REALLY found my 2nd method necessary, because the main idea in my post was to avoid the encodings altogether by doing `StreamReader` and a `sr.ReadLine` to **string**. Plus, your link only talks about it losing bytes after doing a round-trip if you do a `GetString` then a `GetBytes`. I'm not doing that at all - it does the `GetBytes` from the `StreamReader`, which is EXACTLY HOW you are SUPPOSED to do it & lets it be stored as `bytes`, afterwards. You can stream bytes all day. – vapcguy Jan 14 '22 at 19:26
  • 1
    @vapcguy Fair enough. Have a great day. – mjwills Jan 15 '22 at 21:29