Is there a Base64Stream for .NET?

11,851

Solution 1

If you want a stream that converts to Base64, you can put a ToBase64Transform into a CryptoStream:

new CryptoStream(stream, new ToBase64Transform(), CryptoStreamMode.Write)

If you just want to convert a single byte array to Base64, you can simply call Convert.ToBase64String(bytes).

In both cases, you can replace the word To with From.

Solution 2

With the simple answer from @SLaks I have written a simple solution:

/// <summary>
///     Encodes the specified input stream into the specified output stream.
/// </summary>
/// <param name="inputStream">
///     The input stream.
/// </param>
/// <param name="outputStream">
///     The output stream.
/// </param>
/// <param name="lineLength">
///     The length of lines.
/// </param>
/// <param name="dispose">
///     true to release all resources used by the input and output <see cref="Stream"/>;
///     otherwise, false.
/// </param>
/// <exception cref="ArgumentNullException">
///     inputStream or outputStream is null.
/// </exception>
/// <exception cref="ArgumentException">
///     inputStream or outputStream is invalid.
/// </exception>
/// <exception cref="NotSupportedException">
///     inputStream is not readable -or- outputStream is not writable.
/// </exception>
/// <exception cref="IOException">
///     An I/O error occured, such as the specified file cannot be found.
/// </exception>
/// <exception cref="ObjectDisposedException">
///     Methods were called after the inputStream or outputStream was closed.
/// </exception>
public static void EncodeStream(Stream inputStream, Stream outputStream, int lineLength = 0, bool dispose = false)
{
    if (inputStream == null)
        throw new ArgumentNullException(nameof(inputStream));
    if (outputStream == null)
        throw new ArgumentNullException(nameof(outputStream));
    var si = inputStream;
    var so = outputStream;
    try
    {
        int i;
        var cs = new CryptoStream(si, new ToBase64Transform(), CryptoStreamMode.Read);
        var ba = new byte[lineLength < 1 ? 4096 : lineLength];
        var sep = new byte[] { 0xd, 0xa };
        while ((i = cs.Read(ba, 0, ba.Length)) > 0)
        {
            so.Write(ba, 0, i);
            if (lineLength < 1 || i < ba.Length)
                continue;
            so.Write(sep, 0, sep.Length);
        }
    }
    finally
    {
        if (dispose)
        {
            si.Dispose();
            so.Dispose();
        }
    }
}

/// <summary>
///     Decodes the specified input stream into the specified output stream.
/// </summary>
/// <param name="inputStream">
///     The input stream.
/// </param>
/// <param name="outputStream">
///     The output stream.
/// </param>
/// <param name="dispose">
///     true to release all resources used by the input and output <see cref="Stream"/>;
///     otherwise, false.
/// </param>
/// <exception cref="ArgumentNullException">
///     inputStream or outputStream is null.
/// </exception>
/// <exception cref="ArgumentException">
///     inputStream or outputStream is invalid.
/// </exception>
/// <exception cref="NotSupportedException">
///     inputStream is not readable -or- outputStream is not writable.
/// </exception>
/// <exception cref="IOException">
///     An I/O error occured, such as the specified file cannot be found.
/// </exception>
/// <exception cref="ObjectDisposedException">
///     Methods were called after the inputStream or outputStream was closed.
/// </exception>
public static void DecodeStream(Stream inputStream, Stream outputStream, bool dispose = false)
{
    if (inputStream == null)
        throw new ArgumentNullException(nameof(inputStream));
    if (outputStream == null)
        throw new ArgumentNullException(nameof(outputStream));
    var si = inputStream;
    var so = outputStream;
    try
    {
        var bai = new byte[4096];
        var bao = new byte[bai.Length];
        using (var fbt = new FromBase64Transform())
        {
            int i;
            while ((i = si.Read(bai, 0, bai.Length)) > 0)
            {
                i = fbt.TransformBlock(bai, 0, i, bao, 0);
                so.Write(bao, 0, i);
            }
        }
    }
    finally
    {
        if (dispose)
        {
            si.Dispose();
            so.Dispose();
        }
    }
}

I only use CryptoStream to encode because I've found it has problems decoding Base64 hahes with line breaks, while FromBase64Transform can do that easily without CryptoStream. I hope the rest is clear enough that I do not have to explain anything.

Example:

const int lineLength = 76;
const string sourcePath = @"C:\test\file-to-encode.example";
const string encodedPath = @"C:\test\encoded-example.base64";
const string decodedPath = @"C:\test\decoded-base64.example";

// encoding
using(var fsi = new FileStream(sourcePath, FileMode.Open))
    using (var fso = new FileStream(encodedPath, FileMode.Create))
        EncodeStream(fsi, fso, lineLength);

// decoding
using(var fsi = new FileStream(encodedPath, FileMode.Open))
    using (var fso = new FileStream(decodedPath, FileMode.Create))
        DecodeStream(fsi, fso);

Solution 3

This should do what you are looking for:

http://mews.codeplex.com/SourceControl/changeset/view/52969#392973

Solution 4

System.Convert provides that, here is a code sample that might help

private string EncodeBase64(string toEncode)
{
  byte[] toEncodeAsBytes = System.Text.ASCIIEncoding.ASCII.GetBytes(toEncode);
  string returnValue = System.Convert.ToBase64String(toEncodeAsBytes);
  return returnValue;
}

Solution 5

It looks like there is a Base64Stream class. Maybe it'll help future readers.

http://referencesource.microsoft.com/#system/net/System/Net/mail/Base64Stream.cs

Share:
11,851
Cheeso
Author by

Cheeso

I'm a longtime hacker and software practitioner. Creator of IIRF, DotNetZip, ReloadIt, CleanModQueue and a bunch of other Apigee-related tools and scripts. Maintainer of csharp-mode and a few other emacs-y things . I'm a Polyglot: Java, JavaScript, golang, a little PHP, C#, some VB.NET, C, XSLT, Powershell, elisp of course. Currently most of the work I do is JavaScript and NodeJS. I work for Google. We're hiring API geeks around the world. see: https://careers.google.com/jobs#t=sq&amp;q=j&amp;li=20&amp;l=false&amp;jlo=en-US&amp;j=apigee See my blog ...or my Github profile ...or my LinkedIn profile

Updated on June 24, 2022

Comments

  • Cheeso
    Cheeso almost 2 years

    If I want to produce a Base64-encoded output, how would I do that in .NET?

    I know that since .NET 2.0, there is the ICryptoTransform interface, and the ToBase64Transform() and FromBase64Transform() implementations of that interface.

    But those classes are embedded into the System.Security namespace, and require the use of a TransformBlock, TransformFinalBlock, and so on.

    Is there an easier way to base64 encode a stream of data in .NET?

  • SLaks
    SLaks about 14 years
    You don't need a custom stream class; you can just use a CryptoStream. See my answer.
  • Cheeso
    Cheeso about 14 years
    Looks easy. Can you set RFC 2045 line lengths on that stream?
  • SLaks
    SLaks about 14 years
    You can call Convert.ToBase64String(bytes, Base64FormattingOptions.InsertLineBreaks) However, ToBase64Transform does not expose that option.
  • Cheeso
    Cheeso about 14 years
    Useful, but in my case, I don't want to use the ToBase64String. It's not a stream and is likely to not work very well with large data.
  • Cheeso
    Cheeso about 14 years
    ok that's odd. So if I wanna create a base64 doc for MIME-attach purposes (a la RFC 2045), then I can't used that, but if I convert FROM a base64 doc, it would work?
  • Cheeso
    Cheeso about 13 years
    yes, but I couldn't figure out how to do RFC2045-compliant line lengths with the builtin class. So I did need a custom class, as far as I am aware.
  • John
    John over 12 years
    @Cheeso how Can i decompress the stream outputed from your code snippet?
  • Cheeso
    Cheeso about 12 years
    Well you'd just run the content through a compressor. But compressing a base64 string produced from compression seems like the wrong idea. The original content is compressed, then it is base64 encoded. Compressing the output would have the result of removing the benefits of base64 encoding. Also it likely wouldn't have any good result, since the content is already compressed therefore the base64 encoding of said content will be mostly incompressible.
  • Rhult
    Rhult over 10 years
    @Cheeso, I'm interested in taking a look at your Base64Stream, but that winisp.net link appears to be dead. Do you have it anywhere else?
  • tjmoore
    tjmoore over 7 years
    Dead links. Please don't post links, post the code.
  • JBert
    JBert over 6 years
    This does not completely answer the original question: that class is marked internal and you can't just copy the source code because it is for reference only.
  • eli
    eli over 6 years
    You are right, I didn't think you can't copy the source.
  • ΩmegaMan
    ΩmegaMan almost 5 years
    You ought to publish it, in a Nuget package. :-)