76

I have a byte[] and I'm looking for the most efficient way to base64 encode it.

The problem is that the built in .Net method Convert.FromBase64CharArray requires a char[] as an input, and converting my byte[] to a char[] just to convert it again to a base64 encoded array seems pretty stupid.

Is there any more direct way to do it?

[[EDIT:]] I'll expaling what I want to acheive better - I have a byte[] and I need to return a new base64 encoded byte[]

sternr
  • 6,216
  • 9
  • 39
  • 63

8 Answers8

249

Byte[] -> String: use system.convert.tobase64string

Convert.ToBase64String(byte[] data)

String -> Byte[]: use system.convert.frombase64string

Convert.FromBase64String(string data)
Mrchief
  • 75,126
  • 20
  • 142
  • 189
Stephan Schinkel
  • 5,270
  • 1
  • 25
  • 42
  • This returns a string, and I want a byte[] – sternr Aug 29 '12 at 12:59
  • 4
    can you explain a usecase where you need a base64 byte[] as byte[] ? i never in my live had this need. – Stephan Schinkel Aug 29 '12 at 13:04
  • 1
    Converting a string into bytes is another story. Use Encoding.ASCII.GetBytes(theString) – BlueM Aug 29 '12 at 13:04
  • 62
    This is why you _always_ scroll down to the second answer, lol. – DaveMorganTexas May 16 '14 at 02:44
  • Use case: You need to return a binary something, e.g. an image, via a RESTFUL API response. The binary image is in your byte[] and the base64 string is contained in the JSON response body. – robnick Dec 12 '18 at 22:09
  • 2
    @robnick: that's a huge no-go. every binary data that is getting base64'd is approx. 33% larger in size. so that's not really a useful usecase. nevertheless your usecase is just covered with byte[] -> string. – Stephan Schinkel Dec 13 '18 at 13:10
  • @StephanSchinkel for me this was a valid use-case: https://stackoverflow.com/questions/51981473/downloaded-pdf-looks-empty-although-it-contains-some-data I needed to download pdf/xls/csv files via xhr and they were all messed up wingdings etc., took me a lot to figure out why. – Kristóf Tóth Jul 26 '19 at 06:47
  • @KristófTóth ok. but nonetheless what you have implemented is a hack and not a solution. the hack has the tradeoff of a 33% larger file download. i never had such a problem and cannot find anything online regarding your problem. – Stephan Schinkel Aug 08 '19 at 08:44
  • 1
    @StephanSchinkel Just try to implement downloading pdf or similar formatted files via ajax requests and you will have this problem. :) E.g. you don't have the option to open a new tab or window the current window has to be uninterrupted and in focus all the way. I don't think that 33% of any similarly formatted file counts as a very bad trade-off with the bandwidths of our time. I'm not saying its the proper way. But sometimes the business requirements demand it, thus its valid. – Kristóf Tóth Aug 16 '19 at 20:07
  • 1
    If you need to download a pdf or "formatted file" with ajax then just download it as a binary responsetype. No reason to convert it to text. – forresthopkinsa Feb 19 '20 at 22:11
21

Base64 is a way to represent bytes in a textual form (as a string). So there is no such thing as a Base64 encoded byte[]. You'd have a base64 encoded string, which you could decode back to a byte[].

However, if you want to end up with a byte array, you could take the base64 encoded string and convert it to a byte array, like:

string base64String = Convert.ToBase64String(bytes);
byte[] stringBytes = Encoding.ASCII.GetBytes(base64String);

This, however, makes no sense because the best way to represent a byte[] as a byte[], is the byte[] itself :)

Eren Ersönmez
  • 38,383
  • 7
  • 71
  • 92
  • 2
    What if you would need to send the Base64 encoded form over the network? or to a file? then you will need it translated to byte[]. don't be too quick to say something makes no sense. – Amit Bens Jul 28 '13 at 12:28
  • 1
    @AmitBens sure, but if the API takes a byte[] then you can typically send the original bytes. Maybe you're thinking of a case where you embed the byte[] within a textual structure (e.g. JSON) and then send the larger structure over a binary protocol (e.g. TCP)? You'd hardly ever have to directly convert a byte array to base64 only to convert it back to a byte[] again. – Eren Ersönmez Jul 28 '13 at 15:25
  • 1
    @erenEsonmez - MIME for email sending, uses base64 for attachments or messages not in ascii encoding, etc. you can hardly send an email without sending a base64 representation over the wire. – Amit Bens Jul 29 '13 at 11:56
  • 1
    @ErenErsönmez Also note that some APIs require data be provided as a Base64 string (e.g. shopify). I agree its a silly but that's why people might need this. – Maxim Gershkovich Apr 04 '18 at 13:16
  • This is dangerous! I've tried to apply this logic to a PNG image and the byte[] returned wrong array of bytes (both ASCII and UTF8). I would advise to use Convert.FromBase64String(base64String) instead. – GeorgiG Mar 30 '22 at 15:15
  • 1
    @GeorgiG unlike your use case, OP wasn't interested in roundtrip of original bytes. See the discussions around `FromBase64String` in the question comments. – Eren Ersönmez Apr 04 '22 at 18:57
6

Here is the code to base64 encode directly to byte array (tested to be performing +-10% of .Net Implementation, but allocates half the memory):

    static public void testBase64EncodeToBuffer()
    {
        for (int i = 1; i < 200; ++i)
        {
            // prep test data
            byte[] testData = new byte[i];
            for (int j = 0; j < i; ++j)
                testData[j] = (byte)(j ^ i);

            // test
            testBase64(testData);
        }
    }

    static void testBase64(byte[] data)
    {
        if (!appendBase64(data, 0, data.Length, false).SequenceEqual(System.Text.Encoding.ASCII.GetBytes(Convert.ToBase64String(data)))) throw new Exception("Base 64 encoding failed");
    }

    static public byte[] appendBase64(byte[] data
                              , int offset
                              , int size
                              , bool addLineBreaks = false)
    {
        byte[] buffer;
        int bufferPos = 0;
        int requiredSize = (4 * ((size + 2) / 3));
        // size/76*2 for 2 line break characters    
        if (addLineBreaks) requiredSize += requiredSize + (requiredSize / 38);

        buffer = new byte[requiredSize];

        UInt32 octet_a;
        UInt32 octet_b;
        UInt32 octet_c;
        UInt32 triple;
        int lineCount = 0;
        int sizeMod = size - (size % 3);
        // adding all data triplets
        for (; offset < sizeMod;)
        {
            octet_a = data[offset++];
            octet_b = data[offset++];
            octet_c = data[offset++];

            triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;

            buffer[bufferPos++] = base64EncodingTable[(triple >> 3 * 6) & 0x3F];
            buffer[bufferPos++] = base64EncodingTable[(triple >> 2 * 6) & 0x3F];
            buffer[bufferPos++] = base64EncodingTable[(triple >> 1 * 6) & 0x3F];
            buffer[bufferPos++] = base64EncodingTable[(triple >> 0 * 6) & 0x3F];
            if (addLineBreaks)
            {
                if (++lineCount == 19)
                {
                    buffer[bufferPos++] = 13;
                    buffer[bufferPos++] = 10;
                    lineCount = 0;
                }
            }
        }

        // last bytes
        if (sizeMod < size)
        {
            octet_a = offset < size ? data[offset++] : (UInt32)0;
            octet_b = offset < size ? data[offset++] : (UInt32)0;
            octet_c = (UInt32)0; // last character is definitely padded

            triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;

            buffer[bufferPos++] = base64EncodingTable[(triple >> 3 * 6) & 0x3F];
            buffer[bufferPos++] = base64EncodingTable[(triple >> 2 * 6) & 0x3F];
            buffer[bufferPos++] = base64EncodingTable[(triple >> 1 * 6) & 0x3F];
            buffer[bufferPos++] = base64EncodingTable[(triple >> 0 * 6) & 0x3F];

            // add padding '='
            sizeMod = size % 3;
            // last character is definitely padded
            buffer[bufferPos - 1] = (byte)'=';
            if (sizeMod == 1) buffer[bufferPos - 2] = (byte)'=';
        }
        return buffer;
    }
Abrar Jahin
  • 13,970
  • 24
  • 112
  • 161
Amit Bens
  • 1,315
  • 3
  • 12
  • 20
  • 6
    kudos for doing it the hard way. But i will stick to System.Convert. – Florian F Jul 03 '16 at 04:02
  • @FlorianFida Sure! the downside with System.Convert is when you need to get the Base64 into a bigger buffer you end up allocating extra buffers (and easily pollute the LOH/GC if you sizes are>80k), but as long as the code is not used very frequently its definitely safe to keep to your system methods :) – Amit Bens Jul 04 '16 at 06:20
  • 2
    Amit Bens code has a good performance but till the moment you need to convert result to string or char[] (means UTF16). And this is quite often case. Then you will find it slower TWO times then System.Convert.ToBase64String. Just because of one System.Text.Encoding.ASCII.GetString(bytes) at the end. This was very unexpected for me. – Roman Pokrovskij May 10 '17 at 22:40
5
byte[] base64EncodedStringBytes = Encoding.ASCII.GetBytes(Convert.ToBase64String(binaryData))
BlueM
  • 6,523
  • 1
  • 25
  • 30
3

Based on your edit and comments.. would this be what you're after?

byte[] newByteArray = UTF8Encoding.UTF8.GetBytes(Convert.ToBase64String(currentByteArray));
Simon Whitehead
  • 63,300
  • 9
  • 114
  • 138
  • 6
    We know that the base-64 string is going to be in the ASCII range, so it may be more efficient just to use the ASCII encoding directly (since it will be identical to what UTF8 would produce anyway) – Marc Gravell Aug 29 '12 at 13:10
0

You could use the String Convert.ToBase64String(byte[]) to encode the byte array into a base64 string, then Byte[] Convert.FromBase64String(string) to convert the resulting string back into a byte array.

Midrel
  • 44
  • 2
0

To retrieve your image from byte to base64 string....

Model property:

    public byte[] NomineePhoto { get; set; }

    public string NomineePhoneInBase64Str 
    {
        get {
            if (NomineePhoto == null)
                return "";

            return $"data:image/png;base64,{Convert.ToBase64String(NomineePhoto)}";
        } 
    }

IN view:

   <img style="height:50px;width:50px" src="@item.NomineePhoneInBase64Str" />
Rejwanul Reja
  • 1,339
  • 1
  • 17
  • 19
-1
    public void ProcessRequest(HttpContext context)
    {
        string constring = ConfigurationManager.ConnectionStrings["SQL_Connection_String"].ConnectionString;
        SqlConnection conn = new SqlConnection(constring);
        conn.Open();
        SqlCommand cmd = new SqlCommand("select image1 from TestGo where TestId=1", conn);
        SqlDataReader dr = cmd.ExecuteReader();
        dr.Read();
        MemoryStream str = new MemoryStream();

        context.Response.Clear();
        Byte[] bytes = (Byte[])dr[0];
        string d = System.Text.Encoding.Default.GetString(bytes);
        byte[] bytes2 = Convert.FromBase64String(d);
        //context.Response.Write(d);
        Image img = Image.FromStream(new MemoryStream(bytes2));
        img.Save(context.Response.OutputStream, ImageFormat.Png);
        context.Response.Flush();
        str.WriteTo(context.Response.OutputStream);
        str.Dispose();
        str.Close();
        conn.Close();
        context.Response.End();
    }
  • 2
    I can see your answer getting down votes. Please explain your answer to avoid downvotes from the community in the future. –  Jan 12 '19 at 13:18