Visual Basic での Base64 エンコード:完全ガイド
Visual Basic の開発者が25年間向き合ってきた問題があります:JPEG、バイナリの塊、ライセンスファイル、あるいはごく普通の文章を持っているのに、目の前の通路はテキストしか受け付けない。JSON のフィールド、環境変数、メール添付、URL、設定ファイル、テキスト型に設定されたデータベースのカラム - 建物にある他のすべての扉に共通するルールが1つあります:印字可能な文字のみ。Base64 は、バイナリを中に通してくれるドアマンです。あなたのバイトを、文字、数字、プラス、スラッシュ、イコールのストリームとして書き直すので、テキストとして移動するものは何でもそれらを運んでくれます。そして朗報:必要になりうるエンコーダーのすべての部品が、すでに .NET ランタイムの中にあります。パッケージも、コンポーネントも、儀式も不要です。
一気に復習をしましょう。このサイトのホームページではフォーマット自体を深く扱っているからです:Base64 は入力3バイトを受け取り、64記号の文字表から4文字として書き、バイト数が3で割り切れないときは末尾に = 1つか2つを付けます。3に対する4という取引が、エンコードされたデータが元のデータよりだいたい3分の1大きくなる理由であり、エンコードするたびに1回だけ払う、あの有名なサイズの課税です。この記事の残りのすべては、あなたが産むエンコードを、次のシステムがまさに期待するものにするためのものです:正しい文字表、正しいパディング、正しい改行、そして正しい文字セット。
エンコーダーの道具箱:すべて内蔵
エンコード側のランタイムも、デコード側と同じ4つの波で育ってきたので、道具箱にはまだサポートされている選択肢が長く尾を引いています。ここにファミリー全体と、それぞれが作られた役割を示します:
| API | 利用可能になった時期 | 用途 |
|---|---|---|
System.Convert.ToBase64String |
.NET Framework 1.1(2003) | 定番。配列1つがはいり、文字列1つがでる。配列の部分集合、スパン、任意の 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セーフの文字表(+ と / の代わりに - と _)、パディングなし。古いランタイムでは Microsoft.Bcl.Memory NuGetパッケージに載っています。 |
ToBase64Transform + CryptoStream |
.NET Framework 1.1(2003) | ストリーミングエンコード:ファイルをチャンクで読み、エンコードされたテキストを書き出し、巨大な入力でもメモリを平らに保つ。 |
バージョンの全景について:.NET 10 が現在の長期サポートリリースです(2025年11月リリース、2028年11月までサポート)。.NET 8 と .NET 9 は2026年11月までサポートされています。.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 でのエンコード生活の9割は2つの呼び出しで、その順番が大事です:エンコーダーが受け取るのはバイトで、テキストではありません。だから文字列から始まるなら、まずバイトに変えるエンコーディングを選び、その後に初めて 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
この3行の真ん中の部分こそが、この仕事の全技術であり、文字列 "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(テンプレートではデフォルトでオフ - すべてのプロジェクトで有効にする価値あり)がその取り違えをコンパイル時に拾います。
出力の形を整える:パディング、改行、正確なサイズ
同じバイトを2回エンコードしても、正当に2つの異なる文字列が産まれることがあります。違いはすべて、出力の形に集約されます。第一にパディング:入力の長さが3の倍数でないとき、エンコーダーは最後のグループに = 1つか2つを補います。RFC は、あなたが従う仕様がそれ以外のことを言う場合を除き含めるべきだと述べており、ToBase64String はデフォルトで含めます。第二に改行:整形オーバーロードの第2引数、Base64FormattingOptions.InsertLineBreaks は、エンコーダーに CRLF で区切られた76文字の行を出力させます。ちょうど 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文字の2行と、その間の CRLF が1つ
End Sub
End Module
第三に正確なサイズ。バッファやカラムの幅を事前確保したくなるからです。ルールは、入力3バイトごとに4文字、切り上げです:1,000バイトは1,336文字になります。手計算する代わりに、ランタイムには与えられた入力サイズに対するエンコード後の最大長を返すヘルパーがあり、それがバッファ確保に渡すものです:
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
同じ3に対する4という比率が、最も純粋な形のサイズの課税です:エンコードされた値はどれも、運んでいるバイトよりだいたい33パーセント大きいので、その余裕を頭に置いてストレージと転送のサイズを計画してください。そして、刺さる前に知っておく価値のある挙動が1つ:文字列をデコードして、その結果を再エンコードしても、新しい文字列はオリジナルと一致する保証がありません。空白が消え、パディングが正規化されるからです。値を比較する必要があるときは、エンコードされたテキストではなくデコードされたバイトを比較してください。
エンコードの前に文字セットを選ぶ
テキストエンコードの最初のステップが「文字列をバイトへ」だから、あなたが選んだ文字セットが、受け手がデコードしたときに何を見るかを決定します。Visual Basic の文字列はランタイムの内側では UTF-16 ですが、あなたが出すバイトは、向こう側が読み取りに期待しているものに合わせなければなりません。選択肢のメニューは短いです:
Encoding.UTF8:web、API、モダンなもののすべてに正しいデフォルト。この言語が持てるすべての Unicode 文字を往復させる。Encoding.Unicode:UTF-16 リトルエンディアン。パイプの両端が明示的に UTF-16 で合意した .NET プログラム同士なら理にかなった選択。それ以上ではありません。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
2つの異なる Base64 文字列、1つの単語、そして旅を生き残るのは片方だけです。実用のルール:あなたが従う仕様が別の方式を名乗っていない限り、テキストは UTF-8 でエンコードし、それを明示してください。
Base64Url: URL で生き残る文字表
標準の文字表には + と / が含まれていますが、この2文字は URL の中でそれぞれ自分の仕事を持っています。そのため、その文字表で作られた Base64 は、クエリストリングやパスセグメントに載った瞬間に壊れます。RFC 4648 の5節で標準化された修正は、2つの違反者を URL セーフな - と _ に交換し、データの長さがすでにデコーダーにどこで終わるかを教えているので、末尾のパディングは通常落とします。base64url と呼ばれるこのバリアントは、JWT、APIトークン、そして増えゆく API たちの文字表です。.NET 9 はそれに専用のクラスを追加しましたが、知っておく価値のある1つの意見で設計されています:パディングは設計上省略されます:
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
上の例は良い選択です:選ばれたバイトは特殊文字の1つを出現させます - アンダースコアです。標準の文字表にはそこがスラッシュなので、交換が起きたのが見えます。古いランタイムの上にいるなら、同じ文字表は文字の入れ替え2つとトリムで、ドロップインで互換性の得られる結果が手に入ります:
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 クラスをくれます。どちらの道でも、パディングという線引きに注意してください:.NET の Base64Url の出力にはパディングがありませんが、他のエコシステムの一部のライブラリはそれを付けます(いくつかの厳格なデコーダーはそれを要求します)。JWT は、たとえばパディングなしの形式を要求するので、.NET のデフォルトはちょうど正しいです。エコシステムの境界を越えるときは、文字列を送る前に向こう側の期待を確認してください。
ファイルをパックする
ファイルこそが最初のユースケースです:バイナリファイルを、メール、FTP、設定システムが喜んで運んでくれるテキストファイルに変える。Visual Basic ではこの仕事の全体が3つの呼び出しで、そのうち1つが読み、もう1つが書きです:
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 ではなくストレージと帯域で、33パーセントの課税のいつもの請求書です。ファイルが参照するテキストのそばにだけ生きるなら、このパターンはまったく問題ありません。ファイルが大きくて長期間生きるなら、そのチャネルは本当にテキスト形式を必要とするのか問い直してください。
画像:手作業でデータURIを作る
データURI方式(RFC 2397)は、ファイルの内容を URL に直接埋め込みます:data:、メディアタイプ、リテラルの目印 ;base64、コンマ、そしてエンコードされたバイト。ブラウザはこれを使って小さな画像やフォントをインラインにします。WPF はデータURIを直接消費できません - BitmapImage には data: スキームのハンドラーがない - だから慣習的な動きは、プレフィックスを剥がしてバイトを MemoryStream に渡すことです。Visual Basic で URI を組むのは文字列の連結1つで、消費するのは小さな初期化ブロックです:
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 自体が、データURIは短い値にしか役に立たないと警告しており、HTML ドキュメントには属性長の制限があります。だから理にかなった範囲は、アイコン、アバター、サムネイル、小さな背景パターンです。メディアタイプは、実際にエンコードしたバイトと一致しなければなりません。下流の誰も内容からそれを再導出してくれるわけではないので。
HTTP:認証ヘッダーと JSON ペイロード
回線上で、あなたが手作業でエンコードする場所は2つです:HTTP の Basic 認証ヘッダーと、バイナリや事前にエンコードされたデータを持つ JSON フィールド。Basic 認証が最も目立ちます:ヘッダーは単語 Basic、スペース、そしてコロンで結合された username:password の Base64 です。それを組むのはエンコード呼び出し1つ:
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
家ルールが2つ:認証情報は HTTPS 経由でのみ送ること - プレーン HTTP 上の Base64 は服でしかなく、鍵ではない - そして生の認証ヘッダーも、それがデコードされる認証情報も、決してログに出さないこと。
メール添付と MIME 折り返し
Base64 が生計を立ててきたのがメールです。SMTP は7ビット ASCII のために作られているので、バイナリ添付は飛ぶ前にテキストにならなければなりません。MIME 標準(RFC 2045)が選択したのもそこでした:1行76文字で折り返した Base64、Content-Transfer-Encoding: base64 ヘッダーで宣言する。System.Net.Mail クラス群で仕事をするなら、この儀式全体がセットアップ2行で済み、メールライブラリが送信時に折り返しをやってくれるからです:
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 の設定値、環境変数。バイトをエンコードして文字列を保存し、出て行くときにデコードします。エンコード側はいつも同じ一行ですが、ストレージ側には、サイズの課税を具体的にしてくれる制限があります。SQL Server の通常の VARCHAR カラムは8,000文字で止まります(NVARCHAR カラムはその半分の4,000文字で止まり、各 Unicode 文字が2バイトかかるため)- 8,000文字は、33パーセントのオーバーヘッドで上限を越える前にだいたい6,000バイトのバイナリが入る容量で、それを越えると MAX 型に、もっと正直に言えば本物のバイナリカラムに手を伸ばします。Windows では、1つのユーザー定義の環境変数は32,767文字が上限(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 のテキストの中に住み、デコードは起動コードで行われます。エンタープライズコーナーへのレガシー注記を1つ:WCF と XML データ契約は、バイト配列を base64Binary という XML スキーマ型としてシリアライズするので、古い .NET サービスの大きな群れがバイナリをちょうどこの方法で保存しており、その XML に見つける値は素の ToBase64String の出力です。
JWT:コンパクト形式を組む
コンパクト形式の JSON Web Token は、ドットで区切られた base64url の3つの部品:ヘッダー、ペイロード、署名です。最初の2つは素の JSON で、3つ目は、正しいキーの保持者がこのトークンを組み上げたという暗号による証明です。署名なしの形を手作業で組むのは、エンコード2つと文字列の結合ですが、本物の 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 が得られます:どこにもパディングはなく、3つの部すべてが URL セーフな文字です。署名も base64url であることに注意してください。トークン全体が URL や HTTP ヘッダーを生き残らなければならないからです。本番システムでは、System.IdentityModel.Tokens.Jwt パッケージ(Microsoft Entra チームの IdentityModel スイート)がこれらのトークンの構築、署名、検証をやってくれます。キー管理、アルゴリズムの固定、有効期限チェックは、まさにそのレイヤーに属するものです。エンコードを手作業で回すのは、理解のためや小さなツールなら問題ありません。アクセスを守るものはすべて、ライブラリに重さを預けましょう。
落とし穴:VB のエンコーダーが滑る場所
ここでの罠は、言語の癖と出力の形の驚きの混成で、ほとんどはクラッシュではなくデバッグセッション1つ分の代価です:
- Byte と Byte()。エンコーダーが望むのは配列です。Visual Basic では1バイトは
Byte、配列はByte()で、違いは1組の丸括弧です。Option Strict Onなら誤った推測はコンパイルエラーになります。オフなら、代わりに実行時の驚きが来ることがあります。厳密さはオンにし、丸括弧は見失わないようにしましょう。 - Encoding.Default の罠、逆バージョン。ロケールによる分岐の物語は .NET Framework のものです。モダンな .NET では
Defaultは常に UTF-8 なので、同じ文字列はどの機械でも同じようにエンコードされます。機械を越えていくものには、エンコーディングを明示的に名乗り、たいていは UTF-8 に - どちらの世界でも助言は変わりません。 - CRLF は入り込み方を知っている。
InsertLineBreaksは MIME には絶賛されて、URL、JSON、データベースのテキストカラムには恐ろしいもので、誰も頼んでいないキャリッジリターンと改行を挿入します。受け手が折り返された行を期待しているときにだけ使い、迷ったらデフォルトのNoneにする。 - 境界でのパディングの不一致。.NET の
Base64Urlはパディングを出しませんが、他のエコシステムの一部のライブラリは付けます(いくつかの厳格なデコーダーはそれを要求します)。エンコード値がエコシステムを越えるときは、文字列を送る前に向こう側の期待を確認してください。JWT はパディングなしの形式を望み、それが .NET のデフォルトです。 - 往復は同一ではない。折り返され、パディングされた文字列をデコードして再エンコードすると、元のテキストではなく、新しいパディングをつけたきれいな1行が得られます。ロジックがエンコード値の等価を比較するなら、代わりにデコードされたバイトを比較してください。
- サイズの天井は本物です。出力長の式、3バイトごとに4文字の切り上げは、入力だいたい1.5ギガバイトで32ビットの数を越えてしまい、エンコーダーは部分的な文字列の代わりに
OutOfMemoryExceptionで答えます。その規模に近づきうる入力には、代わりにストリームを使ってください(下記)。 - スパンの壁。スパンベースのエンコーダーは、呼び出し側から VB で呼び出せます:
Byte()やChar()配列をそのまま渡せば、コンパイラが変換してくれます。しかしSpanやReadOnlySpan型の変数、フィールド、パラメータを宣言することはできません。コンパイラは「Types with embedded references are not supported in this version of your compiler」で拒否します。VB の慣例は、スパンAPIを素の配列で呼び、スパンを格納しないことです。 - BitConverter は Base64 ではない。
BitConverter.ToString(bytes)は対の間にダッシュを入れた16進数として描画するので、うっかり選んでしまいかねない誤答で、別のシステムがTWFuを期待するところで4D-61-6Eを産みます。Base64 なら、クラスはいつもSystem.Convertです。
速さとサイズ:パフォーマンスの注記
Base64 の「遅いテキストコーデック」の名声は、モダンなランタイムとの接触では生き残れません。.NET の中のエンコーダーは、機械がサポートしているときにハードウェアベクトル化コードを実行し、AVX-512、AVX2、SSE 命令セットに専用の高速パスがあり、AVX-512 パスは1ステップで48バイトを処理します。普通のペイロードなら、定番の ToBase64String 呼び出しは、アルゴリズムがボトルネックになることが稀なほど速く、あなたが感じるコストは33パーセントのサイズの課税と、ホットパスでの中間割当です。小さな値を数百万回エンコードするなら、スパンベース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
注目すべきパターンは、ヘルパーでバッファのサイズを決め、そこにエンコードし、使った先頭部分だけ文字列に変換することです。中間の面を可能な限り小さく保ちます。そして、文字列が居心地の悪くなるほど大きくなったファイルには、ストリーミングの組み合わせがメモリを平らに保ちます:CryptoStream で包まれた ToBase64Transform トランスフォームは入力をチャンクで読み、エンコードされたテキストを書き出すので、2ギガバイトのファイルが一度に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
先の注記を1つ:プレビュー中の .NET 11 ライブラリは、既存の Base64 型に新しい便利メソッドとスパンオーバーロードを追加するので、プレビューを追えるプロジェクトなら道具箱は伸び続け、追えないなら、上記はすべてのサポートリリースで安定しています。
短い歴史:MSXML からスパンへ
.NET はるかに前に、Base64 を必要とした Visual Basic のプログラムは、COM の世界からそれを借りていました。クラシックな VB6 と VBA(今も Excel や Office の中で動いているマクロ言語)の芸当は、代わりに XML DOM の要素を使ったものです:MSXML パーサはノードが DataType を bin.base64 と宣言できるので、自分のバイトをノードの nodeTypedValue に書き、text プロパティを読み返せばエンコードされた文字列が手に入ります。実際の Base64 の計算は DOM がやってくれます(ADO の Stream オブジェクト自身の Charset プロパティは「utf-8」や「iso-8859-1」のような本物の文字セット名しか理解せず「base64」は理解しないので、変換自体には何の役も果たしません)。賢く、どこにでもあるもので、それが「base64 VBA」が何十年も経った今も検索エンジンを照らしている理由です。その時代は2002年に終わり、この言語の最初の .NET バージョンである Visual Basic 7.0 が新しい Common Language Runtime に合流し、.NET Framework は System.Convert と ToBase64String を箱から出して同梱してきました。2003年の .NET Framework 1.1 から、すべての VB プログラムが1つの呼び出しで Base64 をエンコードでき、登録するコンポーネントはありませんでした。
モダンな章は短いです。2018年、.NET Core 2.1 が割当の軽い TryToBase64Chars メソッドと、低レベルなスパンベースの System.Buffers.Text.Base64 クラスを追加しました。2024年、.NET 9 が URLセーフの文字表を Base64Url として標準化し、手作業の Replace 呼び出しの10年間に幕を閉じました。2026年時点では、.NET 10 - 2025年11月リリース - がこれをすべて乗せた長期サポートリリースであり、プレビュー中の .NET 11 ライブラリは新しい世代の便利メソッドを追加しつつあります。2003年の一行からスパン時代へのエンコーダーの物語は、最初からやり直す物語ではなく、同じクラスが速く、精密になっていく物語なのです。
トリビア、VB版
InsertLineBreaksは CRLF を含めて MIME の76文字ルールを正確に再現するので、2026年にあなたのエンコーダーが書く改行は、1990年代にメール標準が定義したものとはバイト単位で同じ形です。- Visual Basic 2005 で追加された
IsNot演算子は、Microsoft の特許出願の対象として一度ニュースになりました。その資格を主張できる言語演算子はほんの一握りです。 - 最初の Visual Basic が登場したのは1991年、World Wide Web が存在する前でした。データURI方式が1998年に現れたときには、Base64 はすでに5年間メール添付を運んでいて、VB はその3年前の1995年の Visual Basic 4 で32ビットの言語に成長していました。
- AVX-512 搭載のハードウェアでは、ランタイムのエンコーダーは1ベクトルステップで48バイトを処理します。博物館のテーブル参照と工場のコンベアベルトの違いです。
My名前空間、2005年の Visual Basic の有名なシュガー層は、Base64 のヘルパーを追加する必要が一度もありませんでした。System.Convertはいつも、1つの名前空間を取り込むだけで届く場所にあり、フレームワークがすでに語っていた物語に VB ランタイムが何も足さない、稀有なケースです。
裏の顔
この記事では、Visual Basic における Base64 のエンコード側を扱いました:道具箱、出力の形の決断、URLセーフの文字表、そしてファイルから JWT までのユースケース。逆方向、届いた文字列を取り込んで、隠れているバイトに戻す作業は、それぞれの挙動、寛容のルール、落とし穴を持っていて、姉妹サイトの伴走デコード記事で細部まで扱われています。そのリンクはちょうどこの行の下にあります。そしてホームページのツールは、小さなペイロードを手でエンコードする最速の道であり続けます。
最終更新: 2026-10-10