Devi lavorare con il formato Base64? Allora questo sito è perfetto per te! Usa il nostro praticissimo strumento online per codificare o decodificare i tuoi dati.

Codifica Base64 in Kotlin: una guida completa

Metà di ogni conversazione sul Base64 riguarda il rileggere dati impacchettati di nuovo in byte. L'altra metà, quella per cui sei sul sito giusto, riguarda il produrre quei dati impacchettati in primo luogo. Da qualche parte nella tua applicazione ci sono byte che devono viaggiare attraverso un canale che capisce solo testo: una stringa JSON, un header HTTP, un'email, un URL, un file di configurazione. Il Base64 è la risposta classica, e Kotlin ha una risposta di prima classe nella libreria standard: la classe Base64 in kotlin.io.encoding, stabile da Kotlin 2.2.

Questa guida passeggia per quello che ti serve davvero quando sei tu a produrre Base64: i quattro schemi preset, la manopola del padding, le regole di a capo a cui si reggono email e certificati, l'alfabeto sicuro per gli URL, da dove vengono i byte, e una serie di scenari del mondo reale con il Kotlin in ciascuno. Il formato in sé, come 3 byte diventano 4 caratteri, da dove viene il =, è coperto sulla home page, quindi qui arriviamo dritti al Kotlin.

Una classe, quattro preset

L'intera API è una singola classe, Base64, nel pacchetto kotlin.io.encoding. Non c'è un oggetto encoder da costruire e nessun builder. Invece, la classe arriva con quattro istanze preset, una per schema RFC, e un oggetto companion che fa da sostituto silenzioso per quella più comune:

IstanzaAlfabetoA capo in codificaPadding in codificaUsala per
Base64.Default+ e /nessunoemette =uso generale, API, data URL
Base64.UrlSafe- e _nessunoemette = (spenglilo)URL, token, JWT
Base64.Mime+ e /CRLF ogni 76 caratteriemette =corpi e allegati di email
Base64.Pem+ e /CRLF ogni 64 caratteriemette =certificati e chiavi private

Il dettaglio di denominazione che fa inciampare la gente: queste sono istanze, non fabbriche. Ogni istanza è un valore immutabile, e cambiare il suo comportamento, tipo il padding, restituisce una nuova istanza invece di mutare quella vecchia. Questo rende i preset sicuri da condividere tra thread e da conservare in oggetti, ed è la ragione per cui l'intera classe può essere un semplice tipo valore senza stato interno.

La tua prima codifica: byte in entrata, stringa in uscita

Ecco il programma più piccolo utile del sito: cinque byte in entrata, una stringa di otto caratteri in uscita. L'input è sempre un ByteArray (o una fetta di uno), e il risultato è una String semplice che puoi mettere ovunque sia permesso il testo:

import kotlin.io.encoding.Base64
fun main() {
  val bytes = "Hello".encodeToByteArray()
  val packed = Base64.encode(bytes)
  println(packed)  // SGVsbG8=
}

Quella singola riga fa più lavoro di quanto sembri. Kotlin ti dà diverse forme della stessa operazione, e tutte si leggono come dice la funzione:

  • encode(bytes) restituisce una String, la forma qui sopra.
  • encodeToByteArray(bytes) restituisce un ByteArray di caratteri ASCII, comodo quando la forma impacchettata stessa deve finire in un altro buffer.
  • encodeIntoByteArray(bytes, destination) scrive in un ByteArray che hai già allocato, il che salta un'allocazione sui percorsi caldi.
  • encodeToAppendable(bytes, builder) aggiunge a qualsiasi cosa che implementa Appendable, tipo una StringBuilder, ed è la soluzione naturale quando stai assemblando un documento più grande.

Tutte e quattro accettano lo stesso intervallo opzionale startIndex e endIndex, quindi puoi impacchettare una fetta di un buffer grande senza prima copiarla. Poiché Base64.Default è l'oggetto companion, puoi anche lasciar cadere l'istanza e scrivere Base64.encode(bytes) come zucchero; entrambe le forme sono la stessa chiamata.

La regola 4/3: quanto diventerà lunga?

Prima di mandare in produzione un encoder, vale la pena sapere esattamente quanto sarà più grosso l'output, perché il Base64 spende caratteri su informazioni che già aveva. Il calcolo è rigido: ogni 3 byte in entrata diventano esattamente 4 caratteri in uscita, quindi qualsiasi resto di 1 o 2 byte consuma ancora un gruppo completo di 4, riempito con = per completare il gruppo. Il risultato per le prime dimensioni:

Byte in ingresso12345678
Caratteri in uscita4448881212

La formula dietro la tabella è 4 * ceil(bytes / 3). Nel caso peggiore un singolo byte diventa 4 caratteri, un sovrapprezzo del 300 percento; dai tre byte in su converge su circa un terzo in più di dati sul filo. Questo è l'intero modello di costo; non c'è variazione per istanza, ed è per questo che conviene deliberare sul Base64 dei payload grandi invece di afferrarlo di riflesso.

Il padding è un'impostazione, non un destino

Sul lato codifica, i caratteri = sono una decisione di politica, e Kotlin la rende di prima classe. Ogni istanza porta una PaddingOption, e withPadding ti consegna una nuova istanza con la manopola spostata. Tutti e quattro i preset partono su PRESENT, ed è per questo che "Hello" esce come SGVsbG8= e non come SGVsbG8;

import kotlin.io.encoding.Base64
fun main() {
  val bytes = "Hello".encodeToByteArray()
  val noPad = Base64.Default.withPadding(Base64.PaddingOption.ABSENT)
  println(Base64.encode(bytes))      // SGVsbG8=
  println(noPad.encode(bytes))       // SGVsbG8
}

Sulla manopola ci sono quattro posizioni. La prima parola del nome decide cosa emette l'encoder; la seconda metà decide quanto sarà rigido il decoder della stessa istanza quando, più tardi, lo userai in direzione inversa tu o la controparte:

PaddingOptionL'encoder emette =Il decoder accetta =
PRESENTsìrichiesto, altrimenti fallisce
ABSENTnovietato, un pad vagante fa fallire
PRESENT_OPTIONALsìin entrambi i casi
ABSENT_OPTIONALnoin entrambi i casi

La scelta più comune al momento della codifica è ABSENT con l'alfabeto UrlSafe, che è esattamente la forma che i JSON Web Token e molti schemi URL si aspettano. La rivedrai tra poco.

Base64url: URL, token e JWT

L'alfabeto classico contiene + e /, e entrambi sono un disastro negli URL: un + in una stringa di query viene di routine letto come uno spazio, e / è il separatore di percorso. La sezione 5 della RFC 4648 definisce la variante sicura per URL, sostituendo con - e _, e Base64.UrlSafe è proprio quello schema. Codificare gli stessi byte che producono un / nell'alfabeto classico mostra lo scambio in azione:

import kotlin.io.encoding.Base64
fun main() {
  val bytes = "Hello?".encodeToByteArray()
  println(Base64.encode(bytes))          // SGVsbG8/
  println(Base64.UrlSafe.encode(bytes))  // SGVsbG8_
}

L'utilizzatore reale canonico è un JWT, il cui header e payload sono base64url senza padding, uniti da punti. Ecco la metà di codifica della costruzione di uno, una forma che dovresti capire anche se è una libreria a firmare il token finale:

import kotlin.io.encoding.Base64
fun main() {
  val header = """{"alg":"HS256","typ":"JWT"}"""
  val payload = """{"sub":"1234567890","name":"John Doe"}"""
  val noPad = Base64.UrlSafe.withPadding(Base64.PaddingOption.ABSENT)
  val h = noPad.encode(header.encodeToByteArray())
  val p = noPad.encode(payload.encodeToByteArray())
  val token = "$h.$p.Ym9nVXNlZlNpZ25hdHVyZUZvckRlbW8"
  println(token)
}

Stampa:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIn0.Ym9nVXNlZlNpZ25hdHVyZUZvckRlbW8

Due avvertimenti meritano qui. Primo, il terzo segmento è una firma, e produrne una genuina serve crittografia vera (un firmatario JCA/JCE o una libreria JWT), mai byte fatti a mano; lo snippet qui sopra dimostra solo la forma di codifica. Secondo, se sei sulla JVM e raggiungi java.util.Base64.getUrlEncoder() per abitudine, nota che mette il padding di default, quindi un output in stile JWT richiede .withoutPadding() lì; il preset Kotlin mette il padding di fabbrica con la stessa evidenza, e ti esci invece con una chiamata withPadding.

A capo: i preset Mime e Pem

Due dei quattro preset avvolgono il loro output in righe corte, e la ragione è storica. I vecchi trasporti email corrompevano le righe lunghe, quindi la sezione 6.8 della RFC 2045 fissa il limite del base64 MIME a 76 caratteri per riga; gli strumenti PKI, seguendo la tradizione più vecchia di PEM, usano 64. Kotlin incorpora entrambe le regole nel preset stesso: il separatore di riga è CRLF, l'a capo cade esattamente al limite, e non c'è un separatore finale in chiusura. Un payload di 200 byte attraverso ogni avvolgitore è così:

import kotlin.io.encoding.Base64
fun main() {
  val data = ByteArray(200) { (it % 251).toByte() }
  println(Base64.Mime.encode(data).lines().maxOf { it.length })  // 76
  println(Base64.Pem.encode(data).lines().maxOf { it.length })   // 64
}

Per quell'input, Mime produce 4 righe e Pem ne produce 5. La prima riga Mime è:

AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4

La trappola da ricordare è la direzione opposta a quella per cui stai scrivendo codice: l'output avvolto non è una riga. Se dai l'output Mime a un consumatore rigido di una sola riga, i CRLF diventano un errore di decodifica, quindi scegli l'avvolgitore per canale, non per comodità. Per API, data URL e qualsiasi cosa moderna, Default è il default giusto, e l'avvolgimento è una faccenda di email e certificati.

Da dove vengono i byte?

Un encoder è onesto solo quanto i byte che gli consegni, e le decisioni interessanti accadono un passo prima che encode venga chiamata. La sorgente più comune è il testo, e l'errore più comune è lasciare che il charset decida in silenzio:

  • text.encodeToByteArray() è sempre UTF-8, su ogni piattaforma. È la scelta giusta per JSON, email e dati web, e quella sbagliata se il testo è Latin-1 o UTF-16 e la controparte decodifica di conseguenza.
  • Sulla JVM puoi scegliere esplicitamente con l'estensione inline text.toByteArray(charset), presente nella libreria standard da Kotlin 1.0 ed è la risposta dal lato Kotlin al getBytes(charset) di Java. Non c'è getBytes su kotlin.String, quindi se scrivi text.getBytes() su una stringa Kotlin, il compilatore te lo dice; l'estensione è la strada.
import kotlin.io.encoding.Base64
fun main() {
  val text = "héllo"
  println(Base64.encode(text.encodeToByteArray()))               // aMOpbGxv
  println(Base64.encode(text.toByteArray(Charsets.ISO_8859_1)))  // aOlsbG8=
}

Stesse cinque lettere, due forme impacchettate diverse, perché i byte erano diversi prima che entrasse in gioco qualsiasi Base64. Se il decoder poi assume UTF-8, la versione Latin-1 decodifica in mojibake, e nessun trucco Base64 a nessuno dei due estremi può riparare un disallineamento di charset.

Le altre sorgenti di byte seguono la stessa forma. Un file è file.readBytes() o path.readBytes() e poi encode. Un buffer pre-allocato usa encodeIntoByteArray(bytes, destination). Un documento in costruzione usa encodeToAppendable(bytes, builder), che restituisce la destinazione così le chiamate si concatenano come metodi builder:

import kotlin.io.encoding.Base64
fun main() {
  val sb = StringBuilder("prefix-")
  Base64.encodeToAppendable("Hello".encodeToByteArray(), sb)
  println(sb)  // prefix-SGVsbG8=
}

E sulla JVM c'è una forma streaming per gli input che non stanno in memoria, ancora marcata sperimentale e importabile con il suo nome. La sorpresa nella denominazione: encodingWith avvolge uno stream di uscita, quindi le scritture fatte attraverso di esso escono come base64, e i byte base64 finiscono nello stream sottostante:

import java.io.ByteArrayOutputStream
import kotlin.io.encoding.Base64
import kotlin.io.encoding.ExperimentalEncodingApi
import kotlin.io.encoding.encodingWith
@OptIn(ExperimentalEncodingApi::class)
fun main() {
  val raw = ByteArray(10_000) { (it % 251).toByte() }
  val packed = ByteArrayOutputStream()
  packed.encodingWith(Base64.Default).use { encoded ->
    encoded.write(raw)
  }
  println(packed.size())  // 13336
}

La regola pratica: encode in memoria per tutto quello che sta, encodingWith per gli stream che non stanno, e un charset esplicito ogni volta che i byte sono in effetti testo.

Note dal campo: HTTP Basic Auth

L'autenticazione HTTP Basic è il caso d'uso Base64 più vecchio su internet, ed è ancora dappertutto nel traffico da servizio a servizio. La RFC 7617 definisce lo schema: prendi utente e password, uniscili con i due punti, metti in base64 il risultato e spediscilo come Basic più uno spazio più la stringa impacchettata nell'header Authorization. In Kotlin:

import kotlin.io.encoding.Base64
fun main() {
  val credentials = "alice:s3cr3t"
  val header = "Basic " + Base64.encode(credentials.encodeToByteArray())
  println(header)  // Basic YWxpY2U6czNjcjN0
}

Perché qui il Base64 e non qualcosa di più forte? Perché il valore di un header deve essere un singolo token stampabile, e il Base64 lo garantisce. L'avvertimento onesto: il Base64 è codifica, non cifratura. Qualsiasi client può invertire YWxpY2U6czNjcjN0 in alice:s3cr3t in un solo passo, ed è per questo che l'autenticazione Basic appartiene solo alle connessioni TLS, idealmente con credenziali a token invece di password umane. Quando analizzi un header così, separa sul due punti esattamente una volta, perché la password può legalmente contenere due punti.

Note dal campo: immagini e data URL

Le data URL integrano asset binari direttamente in HTML, CSS e JSON in modo che il browser non faccia una seconda richiesta. La forma è un media type, una virgola, la parola base64, un'altra virgola, e i byte impacchettati:

import kotlin.io.encoding.Base64
fun main() {
  val png = byteArrayOf(0x89.toByte(), 0x50, 0x4E, 0x47, 0x0D.toByte(), 0x0A.toByte(), 0x1A.toByte(), 0x0A.toByte())
  val dataUrl = "data:image/png;base64," + Base64.encode(png)
  println(dataUrl)  // data:image/png;base64,iVBORw0KGgo=
}

I byte qui sopra sono i primi otto di un file PNG, il numero magico che ogni decoder controlla. Perché il Base64 ci sta: il payload deve essere un token testuale sicuro per URL dentro un markup, e il Base64 è l'unico binario-a-testo ampiamente supportato con una grammatica stabile. L'insidia è la dimensione. Un logo di 300 kilobyte diventa circa 400 kilobyte di markup, e ogni kilobyte in più si paga a ogni caricamento di pagina che lo include. Le data URL sono uno strumento ottimo per icone, avatar e sprite piccoli; sono uno strumento terribile per il video, e persino mediocre per una grande fotografia. Misura prima di integrare.

Note dal campo: allegati email

Lo SMTP è un protocollo testuale che precede qualsiasi concetto di binario, quindi ogni allegato di ogni email che hai mai ricevuto è Base64, avvolto a 76 caratteri, dichiarato con un header Content-Transfer-Encoding: base64. Una parte MIME minima con un piccolo allegato binario è così, con lo slot del corpo riempito per un header di 5 byte %PDF- e generato da Kotlin:

From: sender@example.com
To: receiver@example.com
Subject: report
MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="cut-here"

--cut-here
Content-Type: text/plain; charset="utf-8"

The quarterly report follows as an attachment.

--cut-here
Content-Type: application/pdf
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="report.pdf"

JVBERi0=
--cut-here--

(Il corpo JVBERi0= è il base64 dei cinque byte %PDF-; un report vero si avvolgerebbe su molte righe da 76 caratteri.) Il lato Kotlin è una riga quando hai i byte del file:

import kotlin.io.encoding.Base64
fun main() {
  val pdf = byteArrayOf(0x25, 0x50, 0x44, 0x46, 0x2D)  // "%PDF-"
  println(Base64.Mime.encode(pdf))  // JVBERi0=
}

Le insidie sono disciplina di canale. Usa Mime, non Default, per il corpo, perché un parser MIME rigido si aspetta l'avvolgimento, e una riga Default non avvolta di 10.000 caratteri verrà rifiutata o corrotta da alcuni trasporti. Mantieni il valore dell'header esattamente in minuscolo base64 nella riga Content-Transfer-Encoding, e ricorda che l'avvolgimento è parte del formato: output non avvolto e output avvolto sono rappresentazioni diverse degli stessi byte, e il parser dall'altra parte deve sapere quale sta mangiando.

Note dal campo: API JSON e upload

Quando un'API vuole del binario in un documento JSON, la convenzione è un campo stringa che contiene base64, ed è uno dei pattern più comodi dell'ecosistema perché il JSON ha già una casa per il testo. Con kotlinx.serialization il viaggio di andata e ritorno è diretto:

import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlin.io.encoding.Base64
@Serializable
data class UploadRequest(val name: String, val payload: String)
fun main() {
  val icon = byteArrayOf(0x89.toByte(), 0x50, 0x4E, 0x47)
  val request = UploadRequest("icon.png", Base64.encode(icon))
  val json = Json.encodeToString(UploadRequest.serializer(), request)
  println(json)  // {"name":"icon.png","payload":"iVBORw=="}
}

Perché qui il Base64: il JSON non ha un tipo binario, quindi il payload deve essere testo, e il Base64 è la grammatica binaria meno sorprendente che un consumatore di API riconoscerà senza documentazione. L'insidia è la scala. Il sovrapprezzo 4/3 si paga a ogni richiesta e a ogni risposta, e un upload di 10 megabyte diventa una stringa JSON di 13,3 megabyte che il tuo parser deve trattenere, mettere in escape e validare in memoria. Per i file grandi, multipart/form-data o un corpo binario sono quasi sempre il formato di trasporto migliore; riserva il base64-in-JSON a miniature, icone, firme e blob piccoli dove la comodità supera la tassa.

Note dal campo: configurazione e riga di comando

I due ultimi pattern sono i piccoli che compaiono in ogni codebase. Valori di configurazione, token, chiavi di licenza, a volte piccoli segreti, viaggiano spesso attraverso variabili d'ambiente e file properties come base64 perché il trasporto è solo testuale e il valore può contenere virgolette o a capo. Rileggerli è la stessa danza di due passi al contrario: System.getenv o una ricerca tra le property, poi decodifica. Nella riga di comando, codificare un file per trasporto o ispezione è un programma di dieci righe:

import java.io.File
import kotlin.io.encoding.Base64
fun main(args: Array<String>) {
  require(args.isNotEmpty()) { "usage: b64encode <file>" }
  val bytes = File(args[0]).readBytes()
  val encoded = Base64.encode(bytes)
  File(args[0] + ".b64").writeText(encoded)
  println("Wrote ${encoded.length} characters to ${args[0]}.b64")
}

Eseguito su un file contenente i dieci byte hello file, scrive 16 caratteri, aGVsbG8gZmlsZQ==. Le insidie in entrambi i casi sono le stesse due: il Base64 nella configurazione non è una cassaforte, il valore è a un passo dal testo piano e va trattato come un segreto sul filo in ogni caso, e uno strumento CLI fatto a mano dovrebbe decidere il suo alfabeto con deliberazione, perché un utente che incanala il tuo output in un URL avrà bisogno di UrlSafe, non di Default.

Cosa può andare storto in fase di codifica

La codifica è permissiva sul contenuto: qualsiasi sequenza di byte è un input valido, quindi non c'è un fallimento di "simbolo non valido" come hanno i decoder. Quello che lancia è la geometria, e i messaggi sono abbastanza precisi da essere utili:

SituazioneEccezioneMessaggio
endIndex oltre la fine dell'arrayIndexOutOfBoundsExceptionstartIndex: 0, endIndex: 100, size: 5
startIndex oltre endIndexIllegalArgumentExceptionstartIndex: 3 > endIndex: 2
array di destinazione troppo piccolo per encodeIntoByteArrayIndexOutOfBoundsExceptionThe destination array does not have enough capacity, destination offset: 0, destination size: 2, capacity needed: 8

Due insidie specifiche di Kotlin stanno accanto a queste. La prima è il classico errore int + String: bytes.size + " bytes" non compila, perché il più su un Int non concatena stringhe; la forma di interpolazione "${bytes.size} bytes" è il modo Kotlin. La seconda è la ricerca del charset, che lancia UnsupportedCharsetException per un nome che la JVM non riconosce, tipo Charset.forName("utf-9"), quindi un refuso in un nome di charset è un'eccezione a runtime, non un errore di compilazione, e emerge dove l'encoder gira e non dove il nome è stato digitato.

Le insidie, stile Kotlin

Le trappole qui sotto sono quelle che mordono specificamente gli sviluppatori Kotlin che afferrano la libreria standard per la prima volta:

  • Lasciare che encodeToByteArray() scelga il charset per te. È sempre UTF-8, in silenzio, e una sorgente Latin-1 o UTF-16 si impacchetterà in byte che il decoder non sa rileggere. Decidi il charset con intenzione, con toByteArray(charset) sulla JVM quando non è UTF-8.
  • Afferrare java.util.Base64 per memoria muscolare. Il suo getUrlEncoder() mette il padding di default, che è la forma sbagliata per i JWT a meno che tu non ricordi .withoutPadding(); il preset Kotlin rende la scelta esplicita su entrambi i lati.
  • Dare output avvolto Mime o Pem a un consumatore di una sola riga. I CRLF fanno parte della rappresentazione e faranno fallire un decoder rigido che si aspetta una riga; avvolgi solo quando il canale si aspetta l'avvolgimento.
  • Scrivere text.getBytes() su una stringa Kotlin. Il metodo di Java non è visibile su kotlin.String; l'estensione inline toByteArray(charset), presente da Kotlin 1.0, è il sostituto.
  • Fare girare toolchain vecchie. Il Kotlin di sistema su alcune distribuzioni è ancora 1.3, che precede del tutto il Base64 della libreria standard; la classe serve 1.8.20 per esistere, 2.0.20 per il controllo del padding, e 2.2 per essere stabile.
  • Trattare il Base64 come un livello di sicurezza. È una codifica di trasporto con un'inversa pubblica, di un solo passo. Qualsiasi cosa segreta va cifrata prima di essere impacchettata, mai solo impacchettata.

Scegliere bene: una guida rapida alle decisioni

In caso di dubbio, la decisione è quasi sempre fatta dal canale, non dal contenuto. La versione corta:

  • Base64.Default per API, JSON, data URL e qualsiasi cosa che sia in effetti una riga di testo. L'output con padding è la forma più compatibile sul filo.
  • Base64.UrlSafe con padding ABSENT per token, JWT e qualsiasi cosa che atterri in un segmento di URL o in un parametro di query.
  • Base64.Mime per corpi e allegati di email, dove le righe da 76 caratteri sono un requisito rigido del formato.
  • Base64.Pem per certificati e chiavi private, dove le righe da 64 caratteri sono quello che ogni strumento PKI si aspetta.

Poi due abitudini trasversali: rendi il charset esplicito ogni volta che l'input è testo, e tieni d'occhio il sovrapprezzo 4/3 così che i payload grandi ottengano un canale binario invece di uno base64.

La strada verso lo standard

La strada della libreria standard verso Base64 è abbastanza recente che incontrerai Kotlin più vecchi senza di essa. La classe è apparsa per la prima volta in Kotlin 1.8.20 nell'aprile 2023, marcata sperimentale, con tre istanze e una superficie più semplice: la codifica metteva sempre il padding, e non c'era modo di chiedere di meno. Se hai visto codice dell'era 1.8 che rimuove = dalla fine di una stringa con removeSuffix, quello era l'unico strumento dell'epoca per l'output senza padding, ed è un'abitudine che vale la pena buttare ora. Kotlin 2.2, rilasciato nel giugno 2025, ha stabilizzato l'API e aggiunto l'ultimo pezzo, l'istanza Pem. La manopola PaddingOption e withPadding erano già arrivate nella riga 2.0, nel 2.0.20 per l'esattezza, la prima soluzione completa per controllare il padding in entrambe le direzioni. Gli helper streaming encodingWith e decodingWith restano sperimentali e solo-JVM, ed è così che la libreria standard marca le API su cui vuole più esperienza sul campo prima di congelarle. Dalla riga 2.4.0, il linguaggio è passato anche a una finestra di supporto di 18 mesi per la libreria standard, quindi un progetto fissato a un compilatore 2.4.x, come il rilascio stabile 2.4.10 attuale al momento della stesura, ottiene l'intera API Base64 per la durata di quel ciclo di supporto.

Piccole meraviglie

Alcuni dettagli che rendono la classe più interessante una volta che li conosci:

  • Base64.encode(bytes) senza istanza funziona perché Base64.Default è definito sull'oggetto companion; il companion è lo schema di default, quindi lo zucchero e la forma con nome sono letteralmente lo stesso oggetto.
  • La funzione encodeToAppendable è in stile builder: restituisce l'appendable di destinazione, quindi il pattern documentato è ignorare il valore di ritorno e continuare a usare il tuo builder.
  • Il padding non riempie mai un gruppo intero: una stringa base64 finisce con zero, uno o due caratteri =, e contare il pad ti dice esattamente quanti byte l'originale aveva in avanzo nell'ultima tripla.
  • Pem è il più recente dei quattro preset, entrato in 2.2; l'a capo a 64 caratteri è una convenzione PKI più vecchia della regola RFC 2045 accanto alla quale si trova.
  • Sulla JVM la libreria standard deliberatamente non delega a java.util.Base64; le due implementazioni sono separate, il che tiene il comportamento identico tra piattaforme al costo di un'ottimizzazione commentata che il team Kotlin ha tenuto nell'albero in attesa di un futuro in cui l'API Java lo permetta.
  • Lo stesso rilascio 2.2 che ha stabilizzato Base64 ha anche stabilizzato HexFormat, la classe di formattazione hex in kotlin.text sperimentale da Kotlin 1.9, quindi le codifiche testuali a livello di byte hanno ora una casa stabile nella libreria standard.

In chiusura e dove andare dopo

Produrre Base64 in Kotlin è una lista corta di scelte deliberate: scegli il preset per canale, decidi il padding con intenzione, tieni il charset esplicito quando l'input è testo, e rispetta il sovrapprezzo 4/3 quando il payload è grande. Tutto il resto, file, buffer, appendable, stream, è un sottile involucro attorno alle stesse quattro istanze. L'altra direzione, riportare quel testo impacchettato di nuovo in byte, ha le sue regole di severità, i suoi modi di fallimento e le sue insidie, e l'articolo correlato sul sito gemello copre la decodifica Base64 in Kotlin in profondità.

Ultimo aggiornamento: 2026-09-08

Articolo correlato: Decodifica Base64 in Kotlin: una guida completa