Приходится иметь дело с форматом Base64? Тогда этот сайт идеально вам подойдет! Воспользуйтесь нашим невероятно удобным онлайн-инструментом для кодирования или декодирования ваших данных.

Кодирование Base64 в Visual Basic: полное руководство

Вот задача, с которой разработчики Visual Basic сталкиваются уже двадцать пять лет: у вас есть JPEG, двоичный блок, лицензионный файл или совершенно обычная фраза, а канал перед вами принимает только текст. Поле JSON, переменная окружения, вложение в письме, URL, конфигурационный файл, столбец базы данных, типизированный как текст, и все остальные двери в этом здании делят одно правило: только печатные символы. Base64 - это охранник на входе, который пропускает двоичные данные. Он переписывает ваши байты потоком букв, цифр, плюса, слеша и равно, так что всё, что перемещается текстом, может нести их. И хорошая новость: каждая часть кодировщика, которая вам когда-либо понадобится, уже находится внутри среды выполнения .NET. Без пакетов, без компонентов, без церемоний.

В один выдох, потому что домашняя страница этого сайта уходит вглубь самого формата: Base64 берёт три входных байта и записывает их четырьмя символами из 64-символьного алфавита, добавляя один или два завершающих =, когда число байтов не делится нацело. Обмен четыре-за-три и есть причина, по которой закодированные данные примерно на треть больше оригинала, - знаменитый налог на размер, который вы платите один раз за кодирование. Всё остальное в этой статье - о том, чтобы ваша кодировка делала ровно то, чего от неё ждёт следующая система: правильный алфавит, правильное заполнение, правильные переносы строк и правильная кодировка символов.

Ящик инструментов кодировщика: всё встроено

Сторона кодирования среды выполнения росла теми же четырьмя волнами, что и сторона декодирования, так что в ящике инструментов есть длинный хвост по-прежнему поддерживаемых вариантов. Вот всё семейство и та задача, под которую создан каждый:

API Доступен с Для чего
System.Convert.ToBase64String .NET Framework 1.1 (2003) Классика. На входе один массив, на выходе одна строка, с перегрузками для подмножеств массива, спанов и необязательных переносов строк в стиле MIME.
System.Convert.ToBase64CharArray .NET Framework 1.1 (2003) Записывает закодированные символы в символьный буфер, который вы уже выделили, и возвращает, сколько символов было использовано.
System.Convert.TryToBase64Chars .NET Core 2.1 (2018) Кодирование на спанах с минимальным выделением памяти в символьный спан, который вы предоставляете, с булевым ответом вместо исключения.
System.Buffers.Text.Base64 .NET Core 2.1 (2018) Низкоуровневое кодирование на спанах: записывайте в собственный UTF-8-буфер, раздувайте данные на месте и подбирайте размер буферов через GetMaxEncodedToUtf8Length.
System.Buffers.Text.Base64Url .NET 9 (2024) URL-безопасный алфавит (- и _ вместо + и /) без заполнения. На старых средах выполнения едет в пакете NuGet Microsoft.Bcl.Memory.
ToBase64Transform + CryptoStream .NET Framework 1.1 (2003) Потоковое кодирование: читайте файл кусками, пишите закодированный текст, держите память плоской на огромных входах.

Про картину версий: .NET 10 - текущий выпуск с долгосрочной поддержкой (ноябрь 2025, поддерживается до ноября 2028), .NET 8 и .NET 9 поддерживаются до ноября 2026, а .NET 11 находится в превью с новой пачкой удобных методов Base64 на подходе. Всё, что в таблице выше, стабильно во всех этих версиях. Единственный порог версии - Base64Url: встроен начиная с .NET 9, доступен на .NET Framework 4.6.2 и новее через пакет Microsoft.Bcl.Memory, и это единственный пакет, который эта статья когда-либо попросит вас установить. Чтобы запустить черновой проект, .NET SDK поставляется с Visual Basic в коробке:

dotnet new console -lang VB -o Packer
cd Packer
dotnet run

Ваша первая кодировка: байты на входе, текст на выходе

Девяносто процентов жизни кодирования в Visual Basic - это два вызова, и порядок важен: кодировщик принимает байты, а не текст, так что если вы начинаете со строки, вы сначала выбираете кодировку, чтобы превратить её в байты, и только потом делаете шаг Base64. Вот весь танец:

Imports System
Imports System.Text
Module Encoder
    Sub Main()
        Dim text As String = "Man"
        Dim bytes() As Byte = Encoding.UTF8.GetBytes(text)
        Dim packed As String = System.Convert.ToBase64String(bytes)
        Console.WriteLine(packed)
        ' TWFu
    End Sub
End Module

Вот эта средняя часть из трёх строк и есть всё мастерство, а строка "TWFu" - идеальный дымовой тест для любого кодировщика, который вы пишете. Перегрузки дают вам контроль, когда он нужен. Варианты для подмножеств кодируют срез массива, не выписывая его отдельно, что удобно, когда настоящая нагрузка сидит внутри более крупного буфера:

Imports System
Module SlicePacker
    Sub Main()
        Dim data() As Byte = {1, 2, 3, 4, 5, 6, 7, 8}
        Dim packed As String = System.Convert.ToBase64String(data, 2, 4)
        Console.WriteLine(packed)
        ' AwQFBg==  (были закодированы только байты с 3-го по 6-й)
    End Sub
End Module

И форма массив-в-символы, ToBase64CharArray, записывает в символьный буфер, который вы выделяете, и сообщает, сколько символов она заполнила, - это правильный инструмент, когда приемником является часть более крупной текстовой структуры, которую вы собираете вручную. Обратите внимание на домашнее правило синтаксиса Visual Basic: массив байтов пишется как Byte() с пустыми скобками. Уберите их - и у вас будет одиночный байт, а Option Strict On (в шаблонах выключен по умолчанию - стоит включить в каждом проекте) поймает эту путаницу на этапе компиляции.

Формирование вывода: заполнение, переносы строк и точные размеры

Кодирование одних и тех же байтов дважды может законно дать две разные строки, и все различия сводятся к формированию вывода. Во-первых, заполнение: когда длина входа не кратна трём, кодировщик доводит последнюю группу одним или двумя символами =. RFC говорит включать их, если спецификация, которой вы следуете, не говорит иного, и ToBase64String включает их по умолчанию. Во-вторых, переносы строк: второй параметр перегрузок с форматированием, Base64FormattingOptions.InsertLineBreaks, заставляет кодировщик выдавать строки по 76 символов, разделённые CRLF, - это ровно MIME-правило. Сам MIME использует лимит в 76 символов, близкого родственника старых 64-символьных строк PEM, и оба лимита ведут происхождение от ограничений внутри SMTP. Если ваш потребитель - почтовый конвейер, включайте переносы; если это URL, поле JSON или столбец базы данных, оставляйте их выключенными, потому что невидимый CRLF внутри ваших данных найдёт способ удивить вас позже:

Imports System
Module MimePacker
    Sub Main()
        Dim data(113) As Byte
        For i As Integer = 0 To 113
            data(i) = CByte(i)
        Next
        Dim wrapped As String = System.Convert.ToBase64String(data, Base64FormattingOptions.InsertLineBreaks)
        Console.WriteLine(wrapped.Length)
        ' 154: две строки по 76 символов плюс один CRLF между ними
    End Sub
End Module

В-третьих, точные размеры, потому что вы захотите предварительно выделять буферы и ширину столбцов. Правило: четыре символа на каждые три входных байта, округление вверх: 1000 байтов становится 1336 символами. Вместо того чтобы делать арифметику вручную, в среде выполнения есть вспомогательная функция, которая возвращает максимальную закодированную длину для заданного размера входа, - это то, что вы передаёте в выделение буфера:

Imports System.Buffers.Text
Module Sizing
    Sub Main()
        Dim dataLength As Integer = 1000
        Dim textNeeded As Integer = Base64.GetMaxEncodedToUtf8Length(dataLength)
        Console.WriteLine(textNeeded)
        ' 1336
    End Sub
End Module

Тот же обмен четыре-за-три - это налог на размер в чистом виде: каждое закодированное значение примерно на 33 процента больше несомых им байтов, так что планируйте размеры хранения и передачи с этим запасом. И одно поведение, которое стоит знать, прежде чем оно укусит: если вы декодируете строку, а затем перекодируете результат, новая строка не гарантирована совпасть с исходной, потому что пробельные символы исчезают, а заполнение нормализуется. Когда нужно сравнивать значения, сравнивайте декодированные байты, а не закодированный текст.

Выбор кодировки до кодирования

Поскольку первый шаг кодирования текста - это «строка в байты», выбранная вами кодировка решает, что увидит получатель при декодировании. Строки Visual Basic внутри среды выполнения - это UTF-16, но байты, которые вы выдаёте, должны совпадать с тем, что другая сторона ожидает читать, и меню выбора короткое:

  • Encoding.UTF8: правильный вариант по умолчанию для веба, API и всего современного. Он без потерь проходит туда-обратно для любого символа Unicode, который язык способен удержать.
  • Encoding.Unicode: UTF-16 little-endian. Разумный выбор, когда оба конца трубы - программы .NET, которые явно договорились о UTF-16, и ничего больше.
  • Encoding.ASCII: только 7 бит, и всё остальное будет молча заменено вопросительным знаком. Кодирование «Café» как ASCII даёт байты слова «Caf?», которые декодируются обратно ровно в это, со всеми вопросительными знаками.
  • Encoding.Default: на .NET Framework это была ANSI-кодировка машины, но на .NET (Core) это всегда UTF-8, независимо от локали. Всё равно избегайте его для данных, которыми обмениваетесь - называйте кодировку явно, обычно UTF-8.
Imports System
Imports System.Text
Module CharsetPacker
    Sub Main()
        Dim text As String = "Café"
        Dim utf8() As Byte = Encoding.UTF8.GetBytes(text)
        Dim ascii() As Byte = Encoding.ASCII.GetBytes(text)
        Console.WriteLine(System.Convert.ToBase64String(utf8))
        ' Q2Fmw6k=
        Console.WriteLine(System.Convert.ToBase64String(ascii))
        ' Q2FmPw==  (акцент стал вопросительным знаком)
    End Sub
End Module

Две разные строки Base64, одно слово, и только одно из них переживёт дорогу. Практическое правило: если спецификация, которой вы следуете, не называет другую схему, кодируйте текст как UTF-8 и говорите об этом.

Base64Url: алфавит, который выживает в URL

Стандартный алфавит содержит + и /, и у обоих символов внутри URL свои обязанности, так что Base64, построенный на этом алфавите, ломается в ту самую секунду, когда попадает в строку запроса или сегмент пути. Исправление, стандартизированное в разделе 5 RFC 4648, заменяет двух нарушителей на - и _, которые безопасны в URL, и обычно отбрасывает завершающее заполнение, потому что длина данных и так говорит декодеру, где они заканчиваются. Этот вариант, известный как base64url, - алфавит JWT, API-токенов и всё большего числа API. В .NET 9 для него появился специальный класс, и в нём заложен один принцип, который стоит знать: он по замыслу опускает заполнение:

Imports System.Buffers.Text
Module UrlSafePacker
    Sub Main()
        Dim data() As Byte = {219, 255, 0, 63, 16}
        Dim packed As String = Base64Url.EncodeToString(data)
        Console.WriteLine(packed)
        ' 2_8APxA  (подчёркивание, без завершающего заполнения)
    End Sub
End Module

Пример выше удачный: выбранные байты заставляют появиться один из особых символов - подчёркивание, где в стандартном алфавите был бы слеш, - так что вы можете увидеть замену в действии. Если вы застряли на старой среде выполнения, тот же алфавит - это две замены символов плюс обрезка, и вы получите полностью совместимый результат:

Imports System
Module CompatPacker
    Function ToUrlSafe(ByVal packed As String) As String
        Return packed.Replace("+"c, "-"c).Replace("/"c, "_"c).TrimEnd("="c)
    End Function
End Module

На .NET Framework 4.6.2 или новее пакет Microsoft.Bcl.Memory даёт вам настоящий класс Base64Url вместо этого. В любом случае имейте в виду линию в песке по заполнению: вывод Base64Url в .NET не имеет заполнения, тогда как некоторые библиотеки других экосистем добавляют его (и несколько строгих декодеров настаивают на нём). JWT, например, требует незаполненную форму, так что значение по умолчанию в .NET там как раз правильное. Когда вы пересекаете границу экосистемы, проверяйте ожидания другой стороны, прежде чем отправлять строку.

Упаковка файлов

Файлы - изначальный сценарий применения: превратить двоичный файл в текстовый, который почта, FTP и конфигурационные системы охотно понесут. В Visual Basic вся работа - три вызова, один из которых читает, а один записывает:

Imports System.IO
Module FilePacker
    Sub Main()
        Dim bytes() As Byte = File.ReadAllBytes("photo.png")
        Dim packed As String = System.Convert.ToBase64String(bytes)
        File.WriteAllText("photo.b64", packed)
    End Sub
End Module

Держите соотношение размеров в кармане: фото на 10 мегабайт станет текстовым файлом примерно на 13,4 мегабайта. Операция быстрая на современном железе (об этом ниже), так что стоимость почти всегда - хранилище и канал, а не CPU, и это типичный счёт за тридцатипроцентный налог. Когда файл будет жить рядом с текстом, который на него ссылается, этот паттерн вполне хорош; когда файл большой и долгоживущий, спросите себя, действительно ли каналу нужна текстовая форма.

Изображения: собираем data URI вручную

Схема data URI (RFC 2397) встраивает содержимое файла прямо в URL: data:, тип медиа, литеральный маркер ;base64, запятая и закодированные байты. Браузеры используют их, чтобы встраивать маленькие изображения и шрифты прямо в страницу. WPF не может потреблять data URI напрямую - у BitmapImage нет обработчика схемы data: - так что идиоматичный ход - срезать префикс и отдать байты MemoryStream. Собрать URI в Visual Basic - одна строковая конкатенация, а потребить его - небольшой блок инициализации:

Imports System.IO
Imports System.Windows.Media.Imaging
Module DataUriPacker
    Sub Main()
        Dim bytes() As Byte = File.ReadAllBytes("logo.png")
        Dim dataUri As String = "data:image/png;base64," & System.Convert.ToBase64String(bytes)
        Dim image As New BitmapImage()
        image.BeginInit()
        image.StreamSource = New MemoryStream(System.Convert.FromBase64String(dataUri.Substring(dataUri.IndexOf(","c) + 1)))
        image.EndInit()
        ' теперь image можно присвоить контролу Image
    End Sub
End Module

Сам RFC предупреждает, что data URI полезны только для коротких значений, а HTML-документы налагают собственные ограничения на длину атрибутов, так что разумный диапазон - иконки, аватарки, миниатюры и крошечные фоновые узоры. Тип медиа должен совпадать с теми байтами, которые вы действительно закодировали, потому что никто ниже по цепочке не выведет его заново из содержимого.

HTTP: заголовки авторизации и JSON-нагрузки

На проводе места, где вы будете кодировать вручную, - два: заголовок Basic auth HTTP и поля JSON, которые несут двоичные или заранее закодированные данные. Basic auth самая заметная: заголовок - это слово Basic, пробел и Base64 от username:password, склеенных двоеточием. Собрать его - один вызов кодирования:

Imports System
Imports System.Text
Module AuthPacker
    Function MakeBasicHeader(ByVal user As String, ByVal password As String) As String
        Dim raw() As Byte = Encoding.UTF8.GetBytes(user & ":" & password)
        Return "Basic " & System.Convert.ToBase64String(raw)
    End Function
End Module

Случай с JSON не менее рутинный. Если API хочет изображение или сертификат внутри тела запроса, вы кодируете байты и кладёте строку в нагрузку, а System.Text.Json (в комплекте начиная с .NET Core 3.0) обрабатывает сериализацию вокруг неё:

Imports System.Text.Json
Module ApiPacker
    Function WidgetPayload(ByVal name As String, ByVal imageBytes() As Byte) As String
        Dim payload = New With {
            .name = name,
            .image = System.Convert.ToBase64String(imageBytes)
        }
        Return JsonSerializer.Serialize(payload)
    End Function
End Module

Два домашних правила: отправляйте учётные данные только по HTTPS, потому что по обычному HTTP Base64 - это костюм, а не замок, и никогда не логгируйте сырой заголовок аутентификации или учётные данные, в которые он декодируется.

Вложения в почте и MIME-обёртка

Электронная почта - место, где Base64 заработал на жизнь. SMTP создавался под 7-битный ASCII, поэтому двоичное вложение должно стать текстом, прежде чем оно сможет полететь, и стандарт MIME (RFC 2045) сделал выбор: Base64, обёрнутый по 76 символов в строке, объявленный заголовком Content-Transfer-Encoding: base64. Если вы работаете с классами System.Net.Mail, весь ритуал - это две строки настройки, потому что почтовая библиотека сама делает обёртку при отправке:

Imports System.IO
Imports System.Net.Mail
Imports System.Net.Mime
Module MailPacker
    Sub Main()
        Using message As New MailMessage("me@example.com", "you@example.com")
            message.Subject = "Quarterly report"
            message.Body = "Please find the report attached."
            Using stream As New FileStream("report.bin", FileMode.Open, FileAccess.Read)
                Dim attachment As New Attachment(stream, "report.bin")
                attachment.TransferEncoding = TransferEncoding.Base64
                message.Attachments.Add(attachment)
            End Using
        End Using
    End Sub
End Module

Собирать обёрнутую форму самостоятельно, через Base64FormattingOptions.InsertLineBreaks, нужно только когда вы пишете сырой MIME-текст вручную: тестовая фикстура для почтовых клиентов, устаревший шлюз или инструмент, который выдаёт файлы .eml. Правило в 76 символов - не вкусовое предпочтение; некоторые принимающие системы обрезают более длинные строки, и поэтому лимит десятилетиями держится в стандарте.

Хранение закодированных значений: базы данных, конфигурационные файлы и переменные окружения

Хранилища только с текстом снова и снова просят Base64: столбец базы данных, типизированный как текст, значение в XML-конфигурации, переменная окружения. Вы кодируете байты, храните строку и декодируете её при выходе. Сторона кодирования - всегда тот же однострочник, но у хранилища есть лимиты, которые делают налог на размер осязаемым. Обычный столбец VARCHAR в SQL Server останавливается на 8000 символах (столбец NVARCHAR останавливается на половине этого - 4000 символов, потому что каждый Unicode-символ стоит два байта) - 8000 символов - это место примерно для 6000 байтов двоичных данных, прежде чем тридцатипроцентная надбавка вытолкнет вас за предел, дальше вы тянетесь к типам MAX или, честнее говоря, к настоящему двоичному столбцу. В Windows одна пользовательская переменная окружения ограничена 32767 символами (а на системах эпохи XP так же ограничивался и весь блок окружения), поэтому идея «сложить весь лицензионный блок в переменную окружения» имеет твёрдый потолок:

Imports System
Module EnvPacker
    Sub Main()
        Dim blob() As Byte = {1, 2, 3, 4, 5}
        Dim packed As String = System.Convert.ToBase64String(blob)
        Environment.SetEnvironmentVariable("APP_BLOB", packed)
        Console.WriteLine(packed)
        ' AQIDBAU=
    End Sub
End Module

Конфигурационные файлы следуют той же форме, со значением, живущим в XML- или JSON-тексте, и декодированием, происходящим в вашем стартовом коде. Одно замечание из мира легаси для корпоративного угла: WCF и XML-контракты данных сериализуют массив байтов как тип XML-схемы base64Binary, так что большой пласт старых .NET-сервисов хранит двоичные данные именно так, и значение, которое вы найдёте в том XML, - это обычный вывод ToBase64String.

JWT: собираем компактную форму

JSON Web Token в компактной форме - это три части base64url, разделённые точками: заголовок, пелод и подпись. Первые два - обычный JSON, а третья - криптографическое доказательство того, что этот токен собрал владелец правильного ключа. Собрать неподписанную форму вручную - два кодирования и строковое склеивание, но настоящему JWT нужен шаг подписи, и маленький пример с HMAC-SHA256 делает всё конкретным:

Imports System
Imports System.Buffers.Text
Imports System.Security.Cryptography
Imports System.Text
Module JwtPacker
    Function BuildHs256Jwt(ByVal headerJson As String, ByVal payloadJson As String, ByVal secret() As Byte) As String
        Dim header As String = Base64Url.EncodeToString(Encoding.UTF8.GetBytes(headerJson))
        Dim body As String = Base64Url.EncodeToString(Encoding.UTF8.GetBytes(payloadJson))
        Dim signingInput As String = header & "." & body
        Using hmac As New HMACSHA256(secret)
            Dim signature() As Byte = hmac.ComputeHash(Encoding.UTF8.GetBytes(signingInput))
            Return signingInput & "." & Base64Url.EncodeToString(signature)
        End Using
    End Function
End Module

Запустите его с заголовком {"alg":"HS256","typ":"JWT"} и пелодом на ваш выбор - и результат будет настоящим компактным JWT: нигде нет заполнения, URL-безопасные символы во всех трёх частях. Обратите внимание, что подпись тоже в base64url, потому что весь токен должен выживать в URL или заголовке HTTP. Для производственных систем пакет System.IdentityModel.Tokens.Jwt (набор IdentityModel от команды Microsoft Entra) собирает, подписывает и проверяет такие токены за вас - это тот слой, где должны жить управление ключами, закрепление алгоритма и проверки срока действия. Собирать кодирование вручную - нормально для понимания и для маленьких инструментов; для всего, что охраняет доступ, пусть вес несёт библиотека.

Подводные камни: где спотыкаются VB-кодировщики

Ловушки здесь - смесь языковых привычек и сюрпризов формирования вывода, и большинство из них стоит отладочной сессии, а не падения:

  • Byte против Byte(). Кодировщику нужен массив. В Visual Basic одиночный байт - это Byte, а массив - Byte(), и разница - одна пара скобок. При Option Strict On неверное предположение - ошибка компиляции; с выключенной строгостью вы вместо этого можете получить сюрприз во время выполнения. Держите строгость включённой и скобки на виду.
  • Ловушка Encoding.Default, наоборот. История о различиях по локали - это история .NET Framework: в современном .NET Default всегда UTF-8, так что одна и та же строка кодируется одинаково на каждой машине. Для всего, что пересекает машины, называйте кодировку явно, обычно UTF-8 - совет действует в любом случае.
  • У CRLF есть путь внутрь. InsertLineBreaks прекрасен для MIME и ужасен для URL, JSON и текстовых столбцов баз данных, где он вставляет возврат каретки и перевод строки, которых никто не просил. Используйте его только, когда потребитель ожидает обёрнутые строки, а если сомневаетесь - берите значение по умолчанию None.
  • Несостыковка заполнения на границе. Base64Url в .NET не выдаёт заполнение, тогда как некоторые библиотеки других экосистем добавляют его (и несколько строгих декодеров требуют его). Когда ваше закодированное значение пересекает экосистему, подтвердите ожидания другой стороны, прежде чем отправлять строку; JWT хочет незаполненную форму, что и есть значение по умолчанию в .NET.
  • Путешествие туда-обратно - не тождество. Декодируйте обёрнутую и заполненную строку и перекодируйте её - и получите чистую единую строку со свежим заполнением, а не исходный текст. Если ваша логика сравнивает закодированные значения на равенство, сравнивайте декодированные байты.
  • Потолок размера - настоящая вещь. Формула длины вывода - четыре символа на три байта с округлением вверх - переполняет 32-битный счётчик примерно на 1,5 гигабайте входа, и кодировщик отвечает OutOfMemoryException, а не частичной строкой. Для входов где-то рядом с таким масштабом - идите потоком (ниже).
  • Стена спанов. Кодировщики на спанах вызываемы из VB на месте вызова: передавайте ваши массивы Byte() или Char() прямо, и компилятор сконвертирует их. Но вы не можете объявить переменную, поле или параметр типа Span или ReadOnlySpan; компилятор отказывается с сообщением «Types with embedded references are not supported in this version of your compiler». Идиома VB - вызывать span-API обычными массивами и никогда не хранить спан.
  • BitConverter - это не Base64. BitConverter.ToString(bytes) рисует шестнадцатеричную запись с дефисами между парами, так что это соблазнительно неверный ответ, который производит 4D-61-6E, где другая система ожидает TWFu. Для Base64 класс - System.Convert, каждый раз.

Скорость и размер: заметки о производительности

Репутация Base64 как «медленного текстового кодека» не выдерживает встречи с современной средой выполнения. Кодировщик внутри .NET на машинах, которые это поддерживают, прогоняет аппаратно-векторизованный код, с выделенными быстрыми путями для наборов инструкций AVX-512, AVX2 и SSE, и путь AVX-512 перемалывает 48 байтов за шаг. Для обычных нагрузок классический вызов ToBase64String достаточно быстр, и алгоритм почти никогда не становится узким местом; то, что вы ощущаете, - это тридцатипроцентный налог на размер и, на горячих путях, промежуточные выделения памяти. Если вы кодируете миллионы маленьких значений, API на спанах - это уточнение: TryToBase64Chars записывает в символьный спан, которым вы управляете, и сообщает об успехе булевым значением, а System.Buffers.Text.Base64 заходит дальше, кодируя прямо в UTF-8-буферы, которые вы выделяете, и даже раздувая данные на месте:

Imports System
Imports System.Buffers
Imports System.Buffers.Text
Imports System.Text
Module BufferPacker
    Sub Main()
        Dim data() As Byte = {1, 2, 3, 4, 5}
        Dim textLength As Integer = Base64.GetMaxEncodedToUtf8Length(data.Length)
        Dim buffer(textLength) As Byte
        Dim written As Integer
        Dim consumed As Integer
        Dim status As OperationStatus = Base64.EncodeToUtf8(data, buffer, consumed, written)
        Dim packed As String = Encoding.ASCII.GetString(buffer, 0, written)
        Console.WriteLine(packed)
        ' AQIDBAU=
    End Sub
End Module

Заметьте паттерн: вы подбираете размер буфера помощником, кодируете в него и преобразуете в строку только использованный префикс, что держит промежуточную поверхность настолько малой, насколько это возможно. А для файлов достаточно больших, чтобы строки стали неловкими, потоковая пара держит память плоской: трансформ ToBase64Transform, обёрнутый в CryptoStream, читает ваш ввод кусками и пишет закодированный текст, так что файлу в два гигабайта никогда не придётся становиться строкой в 2,7 гигабайта одним куском:

Imports System.IO
Imports System.Security.Cryptography
Module StreamPacker
    Sub EncodeFile(ByVal inputPath As String, ByVal packedPath As String)
        Using inputStream As New FileStream(inputPath, FileMode.Open, FileAccess.Read)
            Using packedStream As New CryptoStream(New FileStream(packedPath, FileMode.Create), New ToBase64Transform(), CryptoStreamMode.Write)
                Dim buffer(65535) As Byte
                While True
                    Dim read As Integer = inputStream.Read(buffer, 0, buffer.Length)
                    If read = 0 Then Exit While
                    packedStream.Write(buffer, 0, read)
                End While
            End Using
        End Using
    End Sub
End Module

Одна заметка наперёд: превью-библиотеки .NET 11 добавляют существующим типам Base64 новые удобные перегрузки и перегрузки на спанах, так что если ваш проект может следить за превью, ящик инструментов продолжает расти; если не может, всё вышеописанное стабильно на каждом поддерживаемом выпуске.

Короткая история: от MSXML до спанов

Долго до .NET программы Visual Basic, которым нужен был Base64, одолживали его у COM-мира. Классический трюк VB6 и VBA (языка макросов, который до сих пор работает внутри Excel и Office) использовал элемент XML DOM: парсер MSXML позволяет узлу объявить свой DataType как bin.base64, так что если записать ваши байты в nodeTypedValue узла и прочитать обратно его свойство text, вы получите закодированную строку, причём реальную арифметику Base64 делает DOM (собственное свойство Charset объекта Stream ADO понимает только настоящие имена наборов символов, вроде «utf-8» или «iso-8859-1», но не «base64», так что в самом преобразовании оно не участвует). Это было хитро, это было повсюду, и именно поэтому «base64 VBA» до сих пор подсвечивает поисковики спустя десятилетия. Эпоха закончилась в 2002 году, когда первая .NET-версия языка, Visual Basic 7.0, влилась в новый Common Language Runtime, и .NET Framework принёс System.Convert с ToBase64String из коробки. С .NET Framework 1.1 в 2003 году каждая VB-программа могла кодировать Base64 одним вызовом, без единого компонента для регистрации.

Современные главы короткие. В 2018 году .NET Core 2.1 добавил метод TryToBase64Chars с минимальным выделением памяти и низкоуровневый класс на спанах System.Buffers.Text.Base64. В 2024 году .NET 9 стандартизовал URL-безопасный алфавит как Base64Url, положив конец десятилетию ручных вызовов Replace. По состоянию на 2026 год .NET 10 - выпущенный в ноябре 2025 - это выпуск с долгосрочной поддержкой, несущий всё это, и превью-библиотеки .NET 11 добавляют новое поколение удобных методов, так что кодировщик - от однострочника 2003 года до эпохи спанов - это история о том, как один и тот же класс становился быстрее и точнее, а не о том, как всё начинали заново.

Весёлые факты, VB-издание

  • InsertLineBreaks воспроизводит MIME-правило в 76 символов с точностью до байта, включая CRLF, что значит, что переносы строк, которые ваш кодировщик пишет в 2026 году, - байт в байт той же формы, что и переносы, определённые почтовым стандартом в 1990-х.
  • Оператор IsNot, добавленный в Visual Basic 2005, однажды попал в новости как объект заявки на патент Microsoft. Очень немногие операторы языка могут похвастаться этим званием.
  • Самый первый Visual Basic вышел в 1991 году, до того как Всемирная паутина вообще существовала. К тому моменту, когда схема data URI появилась в 1998 году, Base64 уже пять лет носил вложения в почте, а VB три года раньше вырос в 32-битный язык - с Visual Basic 4 в 1995 году.
  • На железе с AVX-512 кодировщик среды выполнения обрабатывает 48 байтов за векторный шаг, и это разница между обращением к таблице в музее и конвейерной лентой на фабрике.
  • Пространство имён My, знаменитый слой синтаксического сахара Visual Basic из 2005 года, никогда не нуждалось в помощнике для Base64. System.Convert всегда был в одном импорте пространства имён, редкий случай, когда VB-среда выполнения не добавила ничего к истории, которую фреймворк уже рассказывал.

Другая сторона

Эта статья покрыла сторону кодирования Base64 в Visual Basic: ящик инструментов, решения по формированию вывода, URL-безопасный алфавит и сценарии применения - от файлов до JWT. Обратное направление - взять входящую строку и превратить её обратно в байты, которые она прячет, - имеет собственный набор поведения, правил прощения и подводных камней, и оно покрыто во всех деталях в сопутствующей статье о декодировании на сестринском сайте. Ссылка на неё находится прямо под этой строкой, а инструмент на домашней странице по-прежнему остаётся самым быстрым способом закодировать маленькую нагрузку вручную.

Последнее обновление: 2026-09-08

Связанная статья: Декодирование Base64 в Visual Basic: полное руководство