BaseN кодировка
BaseN кодировки используются для кодирования двоичных данных в текстовый вид. Где N это размер текстового алфавита используемого для кодирования. Применяются BaseN кодировки для "подготовки данных" к передаче по текстовым протоколам (HTTP, SMTP) или нецифровым каналам (напр. печать на бумаге).
Самый популярный вариант такой кодировки это Base64. Сравниться по частоте применения может только Base16 известный как hexadecimal или просто hex. Инструменты для работы с ними есть в .NET еще с первых версий, но они не очень удобные.
Что есть в .NET Framework (Core)
System.Security.Cryptography
ToBase64Transform/FromBase64Transform
Пара классов для преобразования в/из Base64. С помощью вспомогательного класса CryptoStream его можно использовать для потоковой обработки Stream.
using System.Security.Cryptography;
var base64Transform = new ToBase64Transform();
var output = new MemoryStream();
var base64Encoder = new CryptoStream(output, base64Transform, CryptoStreamMode.Write);
base64Encoder.Write(new byte[] { 122 }, 0, 1);
base64Encoder.Close();
// output.ToArray() -> byte[4] { 101, 103, 61, 61 } aka "eg=="
System.Convert
ToBase64String/FromBase64String
Пара функции для преобразования массива байтов в Base64 строку и обратно.
using System;
var bytes = System.Convert.FromBase64String("eg==")
// bytes -> 122
System.BitConverter
Функция преобразования массива байтов в Base16 (hexadecimal) строку, где каждый байт разделен дефизом. Пример: 0A-C0-D3
using System;
var hexString = BitConverter.ToString(new byte[] { 122, 122 });
// hexString -> "7A-7A"
System.Runtime.Remoting.Metadata.W3cXsd2001
SoapHexBinary (Framework-only)
Класс позволяющий преобразовывать массив байтов в Base16 (hexadecimal) строку и обратно.
using System.Runtime.Remoting.Metadata.W3cXsd2001;
var result = SoapHexBinary.Parse("A012");
// result.Value -> byte[];
System.Buffers.Text
Base64 (Core or System.Memory package)
Удобный класс для работы Base64 в режиме потока. Можно толкать Span'ы с байтами и получать результат в свой Span байтов.
Что предлагает Nuget
Multiformats.Base - Base2, 8, 16, 32, 58, 64 (+variants), MIT
Удобная библиотека с очень большим набором вариантов BaseN кодировок. Простое API и есть тесты. Из недостатков: он работает только с массивами.
SimpleBase - Base16, 32, 58, 85 (+variants), streaming, span, Apache-2
Библитека с большим набором BaseN кодировок. Есть поддержка .NET Core и работа со Span'ами. Простое API, есть тесты.
Пакет deniszykov.BaseN
Конечно у всех этих классов и библиотек есть фатальный недостаток.
Помимо этого, большинство бросило поддержку .NET Framework 4.5.
С точки зрения фичей, только класс Base64 умеет в Span<byte> to Span<byte> преобразования (везде это char[] <-> byte[] преобразования). А это частый кейс, когда данные приходят из сети. Эти данные не могут быть "интерпретированы" из byte в char по тому, что char занимает 2 байта в памяти. Т.е. для их преобразования, вышеописанными библиотеками, требуется скопировать их во временный буфер вдвое большего размера чем исходные данные.
В этом пакете функции кодирования/декодирования принимают разные типы входящих данных:
byte[]
char[]
string
byte*
char*
Span<byte>
Span<char>
Все это лежит внутри двух классов BaseNDecoder/BaseNEncoder.
Поддерживаются следующие словари кодирования:
Base16 (hexadecimal/lower/upper)
Base32
ZBase32
Base64
Base64 Url-safe
using deniszykov.BaseN;
var bytes = Base64Convert.ToBytes("eg==");
// bytes[0] -> 122
Более богатый набор предлагает класс BaseNEncoding который реализует System.Text.Encoding.
using deniszykov.BaseN;
var count = BaseNEncoding.Base64Url.GetByteCount("eg=="); // -> 1
var bytes = BaseNEncoding.Base64Url.GetBytes("eg=="); // -> 122
var baseNEncoder = new BaseNEncoder(BaseNAlphabet.Base64Alphabet);
var input = "eg==";
var output = new byte[1024];
baseNEncoder.Convert(input, 0, 4, output, 0, 1, true, out var charsUsed, out var bytesUsed, out var completed);
// output[0] -> 122
Другие примеры "простого" использования лежат тут. Можно использовать свой словарь. Сложных примеров не будет, те кому это надо могут найти их в тестах :)
Install-Package deniszykov.BaseN
DmitryLTL
Как со стримами?
И ещё часто хотелось бы взять данные, gzip и в base64. В одну операцию, без дополнительных подпрыгиваний.
shai_hulud Автор
Если Base64, то самый простой способ это класс ToBase64Transform и CryptoStream.
Если другие, то для стримов удобнее SimpleBase и класс StreamHelper.
Для чтения из сокетов и System.IO.Pipelines уже удобнее можно использовать мою либу т.к. там есть подходящий BaseNEncoder.Convert() принимающие Span{byte}.
Хотя если реализовать ICryptoTransform то можно сесть на паравоз CryptoStream и получить поддержку стримов. Я скорее всего скоро это сделаю у себя в либе в ближайшее время.
DmitryLTL
Как сделать это понятно, я имел ввиду наличие в библиотеке вспомогательных методов чтобы скрыть подобные кишки, а то приходится подобный код из проекта в проект копировать. Может быть конечно не хочется зависимости иметь, но по идее gzip это системная либа.
shai_hulud Автор
Типа такого?
Естественно расширение GZip() я не могу поместить в свою библиотеку т.к. это вне зоны ее ответственности.
shai_hulud Автор
Добавил наследование ICryptoTransform пару расширений:
Тест с примером.