Codifica Base64 in Visual Basic: una guida completa
Ecco un problema che gli sviluppatori di Visual Basic incontrano da venticinque anni: hai una JPEG, un blob binario, un file di licenza o una frase perfettamente ordinaria, e il canale davanti a te accetta solo testo. Un campo JSON, una variabile d'ambiente, un allegato email, un URL, un file di configurazione, una colonna di database tipata come testo, e tutte le altre porte dell'edificio hanno una regola in comune: solo caratteri stampabili. Il Base64 è il controllore di accessi che fa entrare i dati binari. Riscrive i tuoi byte come un flusso di lettere, cifre, segni più, barre e segni di uguale, così qualsiasi cosa che viaggi come testo può portarli. E la buona notizia: ogni pezzo dell'encoder di cui potresti mai aver bisogno è già dentro il runtime .NET. Nessun pacchetto, nessun componente, nessuna cerimonia.
In un fiato, perché la home page di questo sito scava a fondo nel formato stesso: il Base64 prende tre byte in ingresso e li scrive come quattro caratteri di un alfabeto di 64 simboli, aggiungendo uno o due caratteri = in coda quando il numero di byte non è divisibile per tre. È questo scambio di quattro contro tre a far sì che i dati codificati occupino circa un terzo in più dell'originale, la famosa tassa sulle dimensioni che paghi una volta per ogni codifica. Tutto il resto in questo articolo riguarda il far sì che la codifica che produci faccia esattamente ciò che il sistema successivo si aspetta: l'alfabeto giusto, il padding giusto, gli a capo giusti e il set di caratteri giusto.
La cassetta degli attrezzi dell'encoder: tutto è integrato
Il lato codifica del runtime è cresciuto attraverso le stesse quattro ondate del lato decodifica, quindi la cassetta degli attrezzi ha una lunga coda di opzioni ancora supportate. Ecco la famiglia completa e il lavoro per cui ogni singola API è stata costruita:
| API | Disponibile da | A cosa serve |
|---|---|---|
System.Convert.ToBase64String |
.NET Framework 1.1 (2003) | Il classico. Un array in ingresso, una stringa in uscita, con sovraccarichi per sottoinsiemi di array, span e a capo stile MIME facoltativi. |
System.Convert.ToBase64CharArray |
.NET Framework 1.1 (2003) | Scrive i caratteri codificati in un buffer di caratteri che hai già allocato, e restituisce quanti caratteri ha usato. |
System.Convert.TryToBase64Chars |
.NET Core 2.1 (2018) | Codifica basata su span, leggera sulle allocazioni, in uno span di caratteri che fornisci tu, con una risposta booleana al posto di un'eccezione. |
System.Buffers.Text.Base64 |
.NET Core 2.1 (2018) | Codifica a basso livello, basata su span: scrivi nel tuo buffer UTF-8, espandi in loco e dimensiona i buffer con GetMaxEncodedToUtf8Length. |
System.Buffers.Text.Base64Url |
.NET 9 (2024) | L'alfabeto sicuro per URL (- e _ al posto di + e /) senza padding. Sui runtime più vecchi viaggia nel pacchetto NuGet Microsoft.Bcl.Memory. |
ToBase64Transform + CryptoStream |
.NET Framework 1.1 (2003) | Codifica in streaming: leggi un file a pezzi, scrivi il testo codificato in uscita e tieni la memoria piatta su input enormi. |
Per il panorama versioni: .NET 10 è la release con supporto a lungo termine attuale (novembre 2025, supportata fino a novembre 2028), .NET 8 e .NET 9 sono supportati fino a novembre 2026, e .NET 11 è in anteprima con una fresca serie di metodi Base64 di convenienza in arrivo. Tutto quanto nella tabella sopra è stabile su tutte queste versioni. L'unica soglia di versione è Base64Url: integrata a partire da .NET 9, disponibile su .NET Framework 4.6.2 e più recenti attraverso il pacchetto Microsoft.Bcl.Memory, ed è l'unico pacchetto che questo articolo ti chiede mai di installare. Per avviare un progetto provvisorio, il .NET SDK porta Visual Basic già in dotazione:
dotnet new console -lang VB -o Packer
cd Packer
dotnet run
La tua prima codifica: byte in ingresso, testo in uscita
Il novanta per cento della vita di codifica in Visual Basic sono due chiamate, e l'ordine conta: l'encoder accetta byte, non testo, quindi se parti da una stringa scegli prima una codifica per trasformarla in byte, e solo allora fai il passo Base64. Ecco il ballo intero:
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
Quella sezione centrale di tre righe è l'intero mestiere, e la stringa "TWFu" è lo smoke test perfetto per qualsiasi encoder scrivi. I sovraccarichi ti danno controllo quando te ne serve. Le forme a sottoinsieme codificano una fetta di un array senza copiarla prima, il che è comodo quando il vero carico utile sta dentro un buffer più grande:
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== (sono stati codificati solo i byte da 3 a 6)
End Sub
End Module
E la forma da array a caratteri, ToBase64CharArray, scrive in un buffer di caratteri che allochi tu e ti dice quanti caratteri ha riempito, ed è lo strumento giusto quando la destinazione fa parte di una struttura di testo più grande che stai costruendo a mano. Nota la regola di casa per la sintassi di Visual Basic: un array di byte si scrive Byte() con le parentesi vuote. Togli quelle e hai un singolo byte, e Option Strict On (spento di default nei modelli - vale la pena attivarlo in ogni progetto) cattura l'errore al momento della compilazione.
Dare forma all'output: padding, a capo e dimensioni esatte
Codificare gli stessi byte due volte può legittimamente produrre due stringhe diverse, e le differenze derivano tutte dal dare forma all'output. Prima, il padding: quando la lunghezza dell'input non è un multiplo di tre, l'encoder integra il gruppo finale con uno o due caratteri =. L'RFC dice di includerli a meno che lo schema che stai seguendo non dica il contrario, e ToBase64String li include di default. Secondo, gli a capo: il secondo parametro dei sovraccarichi di formattazione, Base64FormattingOptions.InsertLineBreaks, fa emettere all'encoder righe da 76 caratteri separate da CRLF, che è esattamente la regola MIME. Il MIME stesso usa un limite di 76 caratteri, un parente stretto delle vecchie righe da 64 caratteri del PEM, e entrambi i limiti risalgono a restrizioni dentro lo SMTP. Se il tuo consumatore è una pipeline di posta, attiva gli a capo; se è un URL, un campo JSON o una colonna di database, lasciali spenti, perché un CRLF invisibile dentro i tuoi dati troverà il modo di sorprenderti più tardi:
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: due righe da 76 caratteri più un CRLF in mezzo
End Sub
End Module
Terzo, le dimensioni esatte, perché vorrai pre-allocare buffer e larghezze di colonna. La regola è quattro caratteri per ogni tre byte in ingresso, arrotondato per eccesso: 1000 byte diventano 1336 caratteri. Invece di fare l'aritmetica a mano, il runtime ha un helper che restituisce la lunghezza massima codificata per una data dimensione di input, ed è quello che passi all'allocazione del buffer:
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
Quella stessa proporzione di quattro contro tre è la tassa sulle dimensioni nella sua forma più pura: ogni valore codificato è circa il 33 per cento più grande dei byte che porta, quindi pianifica le dimensioni di archiviazione e trasferimento con quel margine in mente. E un comportamento che vale la pena conoscere prima che ti punga: se decodifichi una stringa e poi ricodifichi il risultato, la nuova stringa non è garantita che combaci con quella originale, perché gli spazi bianchi spariscono e il padding viene normalizzato. Confronta i byte decodificati quando devi confrontare valori, non il testo codificato.
Scegliere il set di caratteri prima di codificare
Poiché il primo passo della codifica di testo va da "stringa a byte", il set di caratteri che scegli decide ciò che il ricevente vede quando decodifica. Le stringhe di Visual Basic sono UTF-16 dentro il runtime, ma i byte che emetti dovrebbero corrispondere a ciò che l'altro lato si aspetta di leggere, e il menu di scelte è corto:
Encoding.UTF8: il predefinito giusto per web, API e tutto ciò che è moderno. Fa il viaggio di andata e ritorno intatto per ogni carattere Unicode che il linguaggio può contenere.Encoding.Unicode: UTF-16 little-endian. Una scelta ragionevole quando entrambe le estremità del tubo sono programmi .NET che hanno concordato esplicitamente UTF-16, e niente di più.Encoding.ASCII: solo 7 bit, e sostituirà silenziosamente tutto il resto con un punto interrogativo. Codificare "Café" in ASCII ti dà i byte per "Caf?", che si decodificherà di nuovo in esattamente quello, punto interrogativo incluso.Encoding.Default: su .NET Framework era la code page ANSI della macchina, ma su .NET (Core) è sempre UTF-8 a prescindere dalla localizzazione. Evitala comunque per i dati che scambi - nomina la codifica esplicitamente, di solito 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== (l'accento è diventato un punto interrogativo)
End Sub
End Module
Due stringhe Base64 diverse, una sola parola, e solo una delle due sopravvive al viaggio. La regola pratica: a meno che il protocollo che segui non nomini uno schema diverso, codifica il testo in UTF-8 e dillo.
Base64Url: l'alfabeto che sopravvive agli URL
L'alfabeto standard contiene + e /, e entrambi i caratteri hanno lavori loro dentro gli URL, quindi il Base64 costruito su quell'alfabeto si rompe nel momento in cui atterra in una stringa di query o in un segmento di percorso. La soluzione, standardizzata nella sezione 5 di RFC 4648, scambia i due colpevoli con - e _, che sono sicuri per URL, e di solito lascia cadere il padding in coda perché la lunghezza dei dati dice già al decoder dove finiscono i dati. Questa variante, nota come base64url, è l'alfabeto dei JWT, dei token API e di un numero crescente di API. .NET 9 ha aggiunto una classe dedicata, ed è costruita con un'opinione che vale la pena conoscere: omette il padding per progettazione:
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 (underscore, senza padding in coda)
End Sub
End Module
L'esempio sopra è azzeccato: i byte scelti fanno apparire uno dei caratteri speciali - l'underscore, dove l'alfabeto standard ha una barra - così puoi vedere lo scambio mentre succede. Quando sei su un runtime più vecchio, lo stesso alfabeto è due sostituzioni di caratteri più un taglio finale, e ottieni un risultato direttamente compatibile:
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
Su .NET Framework 4.6.2 o più recente, il pacchetto Microsoft.Bcl.Memory ti dà invece la vera classe Base64Url. In ogni caso, attenzione alla linea di demarcazione sul padding: l'output di Base64Url di .NET non ha padding, mentre alcune librerie di altri ecosistemi lo aggiungono (e alcuni decoder rigorosi ci tengono). Il JWT, per esempio, richiede la forma senza padding, quindi il predefinito di .NET è esattamente giusto lì. Quando attraversi il confine di un ecosistema, controlla l'aspettativa dell'altro lato prima di spedire la stringa.
Impacchettare i file
I file sono il caso d'uso originale: trasformare un file binario in un file di testo che email, FTP e sistemi di configurazione porteranno tutti volentieri. In Visual Basic il lavoro intero sono tre chiamate, una delle quali legge e una delle quali scrive:
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
Tieni la proporzione di dimensioni in tasca: una foto da 10 megabyte diventa un file di testo di circa 13,4 megabyte. L'operazione è veloce su hardware moderno (ne parleremo sotto), quindi il costo è quasi sempre archiviazione e banda, non CPU, che è la solita bolletta di una tassa del 33 per cento. Quando il file vivrà solo accanto al testo che lo riferisce, questo schema va benissimo; quando il file è grande e longevo, chiedi se il canale ha davvero bisogno della forma testo.
Immagini: costruire data URI a mano
Lo schema data URI (RFC 2397) incorpora i contenuti di un file direttamente in un URL: data:, il media type, il marcatore letterale ;base64, una virgola e i byte codificati. I browser li usano per inserire immagini e font piccoli inline. WPF non può consumare un data URI direttamente - BitmapImage non ha un gestore per lo schema data: - quindi la mossa idiomatica è togliere il prefisso e consegnare i byte a una MemoryStream. Costruire l'URI in Visual Basic è una concatenazione di stringa, e consumarlo è un piccolo blocco di inizializzazione:
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()
' ora image può essere assegnato a un controllo Image
End Sub
End Module
Lo stesso RFC avverte che i data URI sono utili solo per valori corti, e i documenti HTML impongono i loro limiti di lunghezza sugli attributi, quindi l'ambito sensato è icone, avatar, miniature e piccoli motivi di sfondo. Il media type deve corrispondere ai byte che hai realmente codificato, perché a valle nessuno lo ri-deriverà dal contenuto.
HTTP: intestazioni di autenticazione e carichi utili JSON
Sul filo, i due luoghi dove codificherai a mano sono l'intestazione di Basic auth HTTP e i campi JSON che portano dati binari o precodificati. La Basic auth è la più visibile: l'intestazione è la parola Basic, uno spazio, e il Base64 di username:password uniti da due punti. Costruirla è una chiamata di codifica:
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
Il caso JSON è altrettanto normale. Se un'API vuole un'immagine o un certificato dentro un corpo di richiesta, codifichi i byte e lasci cadere la stringa nel carico utile, e System.Text.Json (in dotazione dal .NET Core 3.0) gestisce la serializzazione intorno:
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
Due regole di casa: invia le credenziali solo su HTTPS, perché su HTTP semplice il Base64 è un costume, non un lucchetto, e non loggare mai l'intestazione di autenticazione grezza o le credenziali a cui decodifica.
Allegati email e avvolgimento MIME
La posta è dove il Base64 si è guadagnato da vivere. Lo SMTP è stato costruito per ASCII a 7 bit, quindi un allegato binario deve diventare testo prima di poter volare, e lo standard MIME (RFC 2045) ha fatto la scelta: Base64, avvolto a 76 caratteri per riga, dichiarato con un'intestazione Content-Transfer-Encoding: base64. Se lavori con le classi System.Net.Mail, l'intero rituale si riduce a due righe di preparazione, perché la libreria di posta fa l'avvolgimento per te al momento dell'invio:
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
Devi produrre tu la forma avvolta, con Base64FormattingOptions.InsertLineBreaks, solo quando scrivi testo MIME grezzo a mano: una fixture di test di un client di posta, un gateway di vecchia generazione, o uno strumento che sputa file .eml. La regola dei 76 caratteri non è una preferenza di stile; alcuni sistemi riceventi troncano le righe più lunghe, ed è per questo che il limite è sopravvissuto nello standard per decenni.
Memorizzare valori codificati: database, file di configurazione e variabili d'ambiente
L'archiviazione solo testo continua a chiedere Base64: una colonna di database tipata come testo, un valore di configurazione XML, una variabile d'ambiente. Codifichi i byte, memorizzi la stringa, e la decodifichi in uscita. Il lato codifica è sempre la stessa riga unica, ma il lato archiviazione ha limiti che rendono concreta la tassa sulle dimensioni. Una colonna VARCHAR normale in SQL Server si ferma a 8.000 caratteri (una colonna NVARCHAR si ferma alla metà, 4.000 caratteri, perché ogni carattere Unicode costa due byte) - 8.000 caratteri sono spazio per circa 6.000 byte di binario prima che il sovraccarico del 33 per cento ti faccia sforare, oltre i quali prendi i tipi MAX o, più onestamente, una vera colonna binaria. Su Windows, una singola variabile d'ambiente definita dall'utente è limitata a 32.767 caratteri (e sui sistemi dell'era XP l'intero blocco d'ambiente era limitato a quella misura), quindi l'idea di "tenere tutto il blob della licenza in una variabile d'ambiente" ha un soffitto rigido:
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
I file di configurazione seguono la stessa forma, con il valore che vive in testo XML o JSON e la decodifica che avviene nel tuo codice di avvio. Una nota di vecchia generazione per l'angolo aziendale: WCF e i contratti di dati XML serializzano un array di byte come il tipo di schema XML base64Binary, quindi un gran numero di servizi .NET più vecchi memorizza i binari esattamente in questo modo, e il valore che trovi in quell'XML è output semplice di ToBase64String.
JWT: costruire la forma compatta
Un JSON Web Token in forma compatta è composto da tre pezzi di base64url separati da punti: l'intestazione, il carico utile e una firma. I primi due sono JSON semplice, e il terzo è una prova crittografica che un possessore della chiave giusta ha costruito questo token. Costruire a mano la forma non firmata è due codifiche e un'unione di stringhe, ma un JWT vero ha bisogno del passo della firma, e un piccolo esempio HMAC-SHA256 rende tutto concreto:
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
Esegui con l'intestazione {"alg":"HS256","typ":"JWT"} e un carico utile della tua scelta, e il risultato è un JWT compatto autentico: nessun padding da nessuna parte, caratteri sicuri per URL in tutti e tre i pezzi. Nota che anche la firma è base64url, perché l'intero token deve sopravvivere a un URL o a un'intestazione HTTP. Per i sistemi di produzione, il pacchetto System.IdentityModel.Tokens.Jwt (la suite IdentityModel del team Microsoft Entra) costruisce, firma e verifica questi token per te, ed è il livello dove appartengono la gestione delle chiavi, il fissaggio dell'algoritmo e i controlli di scadenza. L'improvvisare la codifica va bene per capire e per strumenti piccoli; per tutto ciò che difende l'accesso, lascia che sia la libreria a portare il peso.
Insidie: dove gli encoder VB scivolano
Le trappole qui sono un misto di abitudini del linguaggio e sorprese nel dare forma all'output, e la maggior parte costa una sessione di debug invece di un crash:
- Byte rispetto a Byte(). L'encoder vuole un array. In Visual Basic un singolo byte è
Bytee un array èByte(), e la differenza è una coppia di parentesi. SottoOption Strict Onun'ipotesi sbagliata è un errore di compilazione; con essa spenta, potresti invece ricevere una sorpresa a runtime. Mantieni il rigore attivo e le parentesi visibili. - La trappola di Encoding.Default, al contrario. La storia della divergenza per localizzazione è quella del .NET Framework: sul .NET moderno,
Defaultè sempre UTF-8, quindi la stessa stringa si codifica allo stesso modo su ogni macchina. Per tutto ciò che attraversa le macchine, nomina la codifica esplicitamente, di solito UTF-8 - il consiglio vale in entrambi i casi. - Il CRLF trova sempre una via.
InsertLineBreaksè meraviglioso per il MIME e terribile per URL, JSON e colonne di testo di database, dove inserisce un ritorno a carro e un feed di riga che nessuno ha chiesto. Usalo solo quando il consumatore si aspetta righe avvolte, e in caso di dubbio usa il predefinitoNone. - Disaccordi sul padding al confine. Il
Base64Urldi .NET non emette padding, mentre alcune librerie di altri ecosistemi lo aggiungono (e alcuni decoder rigorosi lo richiedono). Quando il tuo valore codificato attraversa un ecosistema, conferma l'aspettativa dell'altro lato prima di spedire la stringa; il JWT vuole la forma senza padding, che è il predefinito di .NET. - I viaggi di andata e ritorno non sono identità. Decodifica una stringa avvolta e con padding e ricodificala, e ottieni una riga singola pulita con padding fresco, non il testo originale. Se la tua logica confronta valori codificati per uguaglianza, confronta invece i byte decodificati.
- Il soffitto delle dimensioni è reale. La formula della lunghezza dell'output, quattro caratteri per tre byte arrotondato per eccesso, sfora un conteggio a 32 bit a circa 1,5 gigabyte di input, e l'encoder risponde con un
OutOfMemoryExceptioninvece di una stringa parziale. Per input anche solo vicini a quella scala, usa lo streaming (sotto). - Il muro degli span. Gli encoder basati su span sono richiamabili da VB nel punto di chiamata: passa i tuoi array
Byte()oChar()direttamente dentro e il compilatore li converte. Ma non puoi dichiarare una variabile, un campo o un parametro di tipoSpanoReadOnlySpan; il compilatore rifiuta con "Types with embedded references are not supported in this version of your compiler". L'idioma VB è chiamare le API span con array semplici e non immagazzinare mai uno span. - BitConverter non è Base64.
BitConverter.ToString(bytes)rappresenta l'esadecimale con trattini tra le coppie, quindi è una risposta sbagliata tentante che produce4D-61-6Edove l'altro sistema si aspettaTWFu. Per il Base64, la classe èSystem.Convert, ogni volta.
Velocità e dimensioni: note sulle prestazioni
La reputazione di "lento codec di testo" del Base64 non sopravvive al contatto con il runtime moderno. L'encoder dentro .NET esegue codice vettorizzato in hardware quando la macchina lo supporta, con percorsi veloci dedicati per gli insiemi di istruzioni AVX-512, AVX2 e SSE, e il percorso AVX-512 smaltisce 48 byte a passo. Per carichi utili ordinari, la classica chiamata a ToBase64String è abbastanza veloce che l'algoritmo raramente è il collo di bottiglia; i costi che senti sono la tassa sulle dimensioni del 33 per cento e, per i percorsi caldi, le allocazioni intermedie. Se stai codificando milioni di valori piccoli, le API basate su span sono il raffinamento: TryToBase64Chars scrive in uno span di caratteri che controlli tu e riporta il successo con un booleano, e System.Buffers.Text.Base64 spinge oltre, codificando direttamente in buffer UTF-8 che allochi tu e arrivando persino a espandere i dati in loco:
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
Lo schema da notare è che dimensioni il buffer con l'helper, ci codifichi dentro, e converti in stringa solo il prefisso usato, il che tiene la superficie intermedia piccola quanto possibile. E per i file abbastanza grandi da rendere le stringhe scomode, la coppia in streaming tiene la memoria piatta: la trasformazione ToBase64Transform avvolta in una CryptoStream legge il tuo input a pezzi e scrive il testo codificato in uscita, quindi un file da due gigabyte non deve mai diventare una stringa da 2,7 gigabyte in un sol pezzo:
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
Una nota in avanti: le librerie .NET 11 in anteprima aggiungono nuovi sovraccarichi di convenienza e span ai tipi Base64 esistenti, quindi se il tuo progetto può seguire le anteprime, la cassetta degli attrezzi continua a crescere; se non può, tutto quanto sopra è stabile su ogni release supportata.
Una breve storia: da MSXML agli span
Molto prima di .NET, i programmi Visual Basic che avevano bisogno di Base64 lo prendevano in prestito dal mondo COM. Il trucco classico di VB6 e VBA (il linguaggio di macro che gira ancora dentro Excel e Office) usava invece un elemento XML DOM: il parser MSXML lascia che un nodo dichiari il proprio DataType come bin.base64, quindi scrivendo i tuoi byte nel nodeTypedValue del nodo e rileggendone la proprietà text ottieni la stringa codificata, con il DOM a fare il vero calcolo Base64 (la proprietà Charset dell'oggetto ADO Stream capisce solo nomi di set di caratteri veri come "utf-8" o "iso-8859-1", non "base64", quindi non ha alcun ruolo nella conversione stessa). Era ingegnoso, era dappertutto, ed è per questo che "base64 VBA" accende ancora i motori di ricerca a decenni di distanza. L'era è finita nel 2002, quando la prima versione .NET del linguaggio, Visual Basic 7.0, è entrato nel nuovo Common Language Runtime, e il .NET Framework ha portato System.Convert con ToBase64String in dotazione. Dal .NET Framework 1.1 del 2003, ogni programma VB poteva codificare Base64 con una chiamata e senza componenti da registrare.
I capitoli moderni sono corti. Nel 2018, .NET Core 2.1 ha aggiunto il metodo TryToBase64Chars leggero sulle allocazioni e la classe a basso livello basata su span System.Buffers.Text.Base64. Nel 2024, .NET 9 ha standardizzato l'alfabeto sicuro per URL come Base64Url, chiudendo un decennio di chiamate Replace fatte a mano. A partire dal 2026, .NET 10 - rilasciato a novembre 2025 - è la release con supporto a lungo termine che porta tutto questo, e le librerie .NET 11 in anteprima stanno aggiungendo una nuova generazione di metodi di convenienza, quindi l'encoder, dalla riga unica del 2003 all'era degli span, è la storia della stessa classe che diventa più veloce e più precisa, mai di ricominciare da zero.
Fatti curiosi, edizione VB
InsertLineBreaksriproduce esattamente la regola MIME dei 76 caratteri, CRLF incluso, il che significa che gli a capo che il tuo encoder scrive nel 2026 hanno la stessa forma, byte per byte, di quelli definiti da uno standard di posta negli anni Novanta.- L'operatore
IsNot, aggiunto con Visual Basic 2005, è finito una volta sui giornali come oggetto di una domanda di brevetto Microsoft. Pochissimi operatori di linguaggio possono vantare quella distinzione. - Il primo Visual Basic è uscito nel 1991, prima che il World Wide Web esistesse. Per quando lo schema data URI è apparso nel 1998, il Base64 portava allegati email da cinque anni, e il VB era diventato un linguaggio a 32 bit tre anni prima, con il Visual Basic 4 del 1995.
- Su hardware con AVX-512, l'encoder del runtime elabora 48 byte a passo di vettore, che è la differenza tra una ricerca in tabella in un museo e un nastro trasportatore in una fabbrica.
- L'namespace
My, il famoso livello di zucchero di Visual Basic del 2005, non ha mai avuto bisogno di aggiungere un helper Base64.System.Convertera sempre a un import di namespace di distanza, un caso raro in cui il runtime VB non ha aggiunto nulla a una storia che il framework raccontava già.
L'altro lato
Questo articolo ha coperto il lato codifica del Base64 in Visual Basic: la cassetta degli attrezzi, le decisioni sul dare forma all'output, l'alfabeto sicuro per URL e i casi d'uso dai file ai JWT. La direzione opposta, prendere una stringa in ingresso e riportarla ai byte che nasconde, ha il suo set di comportamenti, regole di perdono e insidie, ed è coperta in pieno dettaglio nell'articolo di decodifica gemello sul sito sorella. Il link si trova proprio sotto questa riga, e lo strumento nella home page resta il modo più rapido per codificare un piccolo carico utile a mano.
Ultimo aggiornamento: 2026-09-08
Articolo correlato: Decodifica Base64 in Visual Basic: una guida completa