Есть ли Base64Stream для .NET? - PullRequest
       47

Есть ли Base64Stream для .NET?

22 голосов
/ 26 марта 2010

Если я хочу создать вывод в кодировке Base64, как мне это сделать в .NET?

Я знаю, что, начиная с .NET 2.0, есть интерфейс ICryptoTransform , и ToBase64Transform () и FromBase64Transform () реализации этого интерфейса.

Но эти классы встроены в пространство имен System.Security и требуют использования TransformBlock, TransformFinalBlock и т. Д.

Есть ли более простой способ base64 кодировать поток данных в .NET?

Ответы [ 6 ]

26 голосов
/ 26 марта 2010

Если вам нужен поток, который преобразуется в Base64, вы можете поместить ToBase64Transform в CryptoStream:

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

Если вы просто хотите преобразовать однобайтовый массив в Base64, вы можете просто вызвать Convert.ToBase64String(bytes).

В обоих случаях вы можете заменить слово To на From.

2 голосов
/ 12 августа 2010

Это должно сделать то, что вы ищете:

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

1 голос
/ 14 июля 2017

Похоже, есть класс Base64Stream. Может быть, это поможет будущим читателям.

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

0 голосов
/ 14 июня 2018

С простым ответом от @ SLaks я написал простое решение:

/// <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();
        }
    }
}

Я использую CryptoStream только для кодирования, потому что обнаружил, что у него есть проблемы с декодированием хэшей Base64 с переносами строк, в то время как FromBase64Transform может легко это сделать без CryptoStream. Надеюсь, все остальное достаточно ясно, и мне не нужно ничего объяснять.

Пример:

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);
0 голосов
/ 26 марта 2010

System.Convert обеспечивает это, вот пример кода, который может помочь

private string EncodeBase64(string toEncode)
    {
      byte[] toEncodeAsBytes
            = System.Text.ASCIIEncoding.ASCII.GetBytes(toEncode);
      string returnValue
            = System.Convert.ToBase64String(toEncodeAsBytes);
      return returnValue;
    }
0 голосов
/ 26 марта 2010

CryptoStream не выполняет окончания строки RFC2045. Поэтому это не сработает для меня.
ToBase64String недопустимо, потому что это не потоковый подход. Я не хочу хранить все данные в памяти одновременно.

Поэтому мне нужны альтернативы.

Ричард Граймс опубликовал один здесь:
http://www.grimes.nildram.co.uk/workshops/encodedStream.htm

Вместо того, чтобы использовать это, из-за требований лицензирования и функций, я написал независимую реализацию, доступную здесь:
http://cheeso.members.winisp.net/srcview.aspx?dir=streams&file=Base64Stream.cs

Он лицензирован под MS-PL .

Чтобы использовать это для сжатия, а затем кодирования файла base64, сделайте следующее:

byte[] working= new byte[1024];
int n;
using (Stream input = File.OpenRead(fileToCompress))
{
    using (Stream output = new FileStream("file.deflated.b64"))
    {
        using (var b64 = new Base64Stream(output, Base64Stream.Mode.Encode))
        {
            b64.Rfc2045Compliant = true; // OutputLineLength = 76;

            using (var compressor = new DeflateStream(b64, CompressionMode.Compress, true))
            {
                while ((n = input.Read(working, 0, working.Length)) != 0)
                {
                    compressor.Write(working, 0, n);
                }
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...