Werk je met Base64-indeling? Dan is deze site perfect voor jou! Gebruik onze handige online tool om je gegevens te coderen of te decoderen.

Base64-codering in Kotlin: een complete gids

De helft van elk Base64-gesprek gaat over het teruglezen van gepakte data naar bytes. De andere helft, waar je op de juiste site voor bent, gaat over het produceren van die gepakte data in de eerste plaats. Ergens in je applicatie zitten bytes die door een kanaal moeten reizen dat alleen tekst begrijpt: een JSON-string, een HTTP-header, een e-mail, een URL, een configuratiebestand. Base64 is het klassieke antwoord, en Kotlin heeft daar een eerstklassig antwoord op in de standaardbibliotheek: de Base64-class in kotlin.io.encoding, stabiel sinds Kotlin 2.2.

Deze gids loopt door wat je écht nodig hebt wanneer jij degene bent die Base64 produceert: de vier voorgedefinieerde schema's, de padding-regelaar, de regels voor regelombraking waar e-mail en certificaten naar leven, het URL-safe alfabet, waar de bytes vandaan komen, en een set echte wereldscenario's met in elk een beetje Kotlin. Het formaat zelf, hoe 3 bytes 4 tekens worden en waar de = vandaan komt, staat op de startpagina, dus gaan we hier direct over de Kotlin.

Eén class, vier voorgedefinieerde instanties

De hele API is één enkele class, Base64, in het kotlin.io.encoding-package. Er is geen encoder-object dat je construeert en geen builder. In plaats daarvan levert de class vier voorgedefinieerde instanties mee, één per RFC-schema, plus een companion-object dat stilletjes instaat voor de meest voorkomende:

InstantieAlfabetRegelombraking bij encodePadding bij encodeWaarvoor je het gebruikt
Base64.Default+ en /geengeeft =algemeen gebruik, API's, data-URLs
Base64.UrlSafe- en _geengeeft = (schakel het uit)URLs, tokens, JWTs
Base64.Mime+ en /CRLF elke 76 tekensgeeft =e-maillichamen en bijlagen
Base64.Pem+ en /CRLF elke 64 tekensgeeft =certificaten en privésleutels

Het naamdetail waar mensen over struikelen: dit zijn instanties, geen fabrieken. Elke instantie is een onmutabele waarde, en als je het gedrag ervan verandert, zoals de padding, krijg je een nieuwe instantie terug in plaats van dat de oude wordt aangepast. Dat maakt de voorgedefinieerde instanties veilig om te delen over threads en op te slaan in objecten, en daarom kan de hele class een simpele waardetype zijn zonder interne staat.

Je eerste encode: bytes binnen, string buiten

Hier is het kleinste nuttige programma op de site: vijf bytes binnen, een string van acht tekens buiten. De invoer is altijd een ByteArray (of een deel van één), en het resultaat is een simpele String die je overal kunt zetten waar tekst mag:

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

Die ene regel doet meer werk dan het lijkt. Kotlin geeft je verschillende vormen van dezelfde operatie, en ze lezen allemaal zoals de functie zegt:

  • encode(bytes) retourneert een String, de vorm hierboven.
  • encodeToByteArray(bytes) retourneert een ByteArray van ASCII-tekens, handig wanneer de gepakte vorm zelf naar een andere buffer gaat.
  • encodeIntoByteArray(bytes, destination) schrijft naar een ByteArray dat je al hebt toegewezen, wat één toewijzing over slaat op hete paden.
  • encodeToAppendable(bytes, builder) voegt toe aan alles wat Appendable implementeert, zoals een StringBuilder, wat de natuurlijke fit is wanneer je een groter document aan het samenstellen bent.

Alles vier accepteert dezelfde optionele startIndex- en endIndex-range, dus je kunt een stuk van een grote buffer pakken zonder het eerst te kopiëren. Omdat Base64.Default het companion-object is, kun je ook de instantie weglaten en Base64.encode(bytes) schrijven als suiker; beide vormen zijn dezelfde aanroep.

De 4/3-regel: hoe lang wordt het?

Voor je een encoder de deur uitstuurt, is het de moeite waard om exact te weten hoe veel groter de uitvoer zal zijn, want Base64 besteedt tekens aan informatie die hij al had. De wiskunde is strikt: elke 3 invoerbytes worden exact 4 uitvoer tekens, dus resterende 1 of 2 bytes verbruiken ook een volledige groep van 4, opgevuld met = om de groep te vullen. Het resultaat voor de eerste paar groottes:

Invoerbytes12345678
Uitvoertekens4448881212

De formule achter de tabel is 4 * ceil(bytes / 3). In het ergste geval wordt één byte 4 tekens, een toeslag van 300 procent; vanaf drie bytes convergeert het naar ongeveer een derde meer data op de draad. Dat is het hele kostenmodel; er is geen verschil per instantie, en daarom moet je doelbewust zijn over Base64-gebruik bij grote payloads in plaats van er van reflex naar te grijpen.

Padding is een instelling, geen lot

Op de encodeerkant zijn de =-tekens een beleidsbeslissing, en Kotlin maakt die een eerstklassige. Elke instantie heeft een PaddingOption, en withPadding reikt je een nieuwe instantie aan met de regelaar verplaatst. Alle vier de voorgedefinieerde instanties starten op PRESENT, daarom komt "Hello" eruit als SGVsbG8= en niet als 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
}

Er zijn vier standen op de regelaar. Het eerste woord van de naam beslist wat de encoder geeft; de tweede helft beslist hoe strikt de decoder van dezelfde instantie zal zijn wanneer jij (of de andere kant) hem later omkeert:

PaddingOptionEncoder geeft =Decoder accepteert =
PRESENTjavereist, alles anders faalt
ABSENTneeverboden, een verdwaald padteken faalt
PRESENT_OPTIONALjabeide kanten
ABSENT_OPTIONALneebeide kanten

De meest voorkomende keus op encodeermoment is ABSENT met het UrlSafe-alfabet, dat is precies de vorm die JSON Web Tokens en veel URL-schema's verwachten. Je komt hem zo weer tegen.

Base64url: URLs, tokens en JWTs

Het klassieke alfabet bevat + en /, en beide zijn rampen in URLs: een + in een query string wordt doorgaans gelezen als een spatie, en een / is de padseparator. RFC 4648 sectie 5 definieert de URL-safe variant, die - en _ inruilt, en Base64.UrlSafe is dat schema. Het encoderen van dezelfde bytes die in het klassieke alfabet een / opleveren, toont de wissel in actie:

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

De canonieke echte-wereldgebruiker is een JWT, waarvan de header en het payload base64url zijn zonder padding, aaneengesloten door punten. Hier is de encodeerkant van het bouwen ervan, een vorm die je moet begrijpen ook al tekent een bibliotheek het uiteindelijke token:

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)
}

Drukt:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIn0.Ym9nVXNlZlNpZ25hdHVyZUZvckRlbW8

Twee waarschuwingen horen hier thuis. Ten eerste is het derde segment een handtekening, en om een echte te produceren heb je echte cryptografie nodig (een JCA/JCE-tekenaar of een JWT-bibliotheek), nooit zelf samengestelde bytes; het fragment hierboven demonstreert alleen de encodeervorm. Ten tweede: als je op de JVM zit en uit gewoonte naar java.util.Base64.getUrlEncoder() grijpt, merk dan op dat die standaard padding gebruikt, dus JWT-achtige uitvoer heeft daar .withoutPadding() nodig; de Kotlin-voorgedefinieerde instantie geeft standaard even luid padding, en je stapt eruit met een withPadding-aanroep in plaats daarvan.

Regelombraking: de Mime- en Pem-instanties

Twee van de vier voorgedefinieerde instanties wikkelen hun uitvoer om naar korte regels, en de reden is historisch. Oude e-mailtransporten verknalden lange regels, dus RFC 2045 sectie 6.8 begrenst MIME-base64 op 76 tekens per regel; PKI-tools gebruiken, volgend de oudere PEM-traditie, 64. Kotlin bakt beide regels in de voorgedefinieerde instantie zelf in: de regeleinde is CRLF, de breuk valt exact op de limiet, en er is geen afsluitend regeleinde op het allerlaatste einde. Zo ziet een payload van 200 bytes eruit door elke wikkelaar:

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
}

Voor die invoer produceert Mime 4 regels en Pem 5. De eerste Mime-regel is:

AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4

De valkuil om je te herinneren is de omgekeerde richting van waarvoor je code schrijft: omgewikkelde uitvoer is niet één regel. Geef je Mime-uitvoer aan een strikte éénregelige consumer, dan worden de CRLFs een decoderingsfout, dus kies de wikkelaar op kanaal, niet op gemak. Voor API's, data-URLs en alles moderne is Default de juiste standaard, en omwikken is een e-mail-en-certificaat-verhaal.

Waar komen de bytes vandaan?

Een encoder is zo eerlijk als de bytes die je hem geeft, en de interessante beslissingen vallen een stap vóórdat encode wordt aangeroepen. De meest voorkomende bron is tekst, en de meest voorkomende fout is het charset laten beslissen zonder erover na te denken:

  • text.encodeToByteArray() is altijd UTF-8, op elk platform. Dat is de juiste keuze voor JSON, e-mails en webdata, en de verkeerde wanneer de tekst Latin-1 of UTF-16 is en de andere kant daarop afgestemd decodeert.
  • Op de JVM kun je expliciet kiezen met de inline-extensie text.toByteArray(charset), die sinds Kotlin 1.0 in de standaardbibliotheek zit en het Kotlin-antwoord is op Java's getBytes(charset). Op kotlin.String bestaat geen getBytes, dus als je text.getBytes() op een Kotlin-string schrijft, zegt de compiler het je; de extensie is de weg.
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=
}

Zelfde vijf letters, twee verschillende gepakte vormen, omdat de bytes al anders waren vóórdat er Base64 bij kwam kijken. Als de decoder later UTF-8 aannemt, dan decodeert de Latin-1-versie naar mojibake, en geen Base64-truc aan welke kant dan ook kan een charset-mismatch herstellen.

Andere bronnen van bytes volgen dezelfde vorm. Een bestand is file.readBytes() of path.readBytes() en dan encode. Een vooraf-toegewezen buffer gebruikt encodeIntoByteArray(bytes, destination). Een document dat in aanbouw is, gebruikt encodeToAppendable(bytes, builder), dat de bestemming retourneert zodat aanroepen in een keten lopen als builder-methoden:

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

En op de JVM is er een streamingvorm voor invoer die niet in het geheugen past, nog steeds experimenteel gemarkeerd en onder zijn eigen naam importeerbaar. De wending in de naamgeving: encodingWith wikkelt een uitvoer-stream, dus schrijfstappen die erdoorheen gaan komen eruit als base64, en de base64-bytes belanden in de onderliggende stream:

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
}

De vuistregel: in-geheugen-encode voor alles wat past, encodingWith voor de streams die niet passen, en een expliciet charset telkens de bytes eigenlijk tekst zijn.

Veldnotities: HTTP Basic-authenticatie

HTTP Basic-authenticatie is het oudste Base64-gebruik op internet, en het zit nog overal in service-naar-service-verkeer. RFC 7617 definieert het schema: pak de gebruiker en het wachtwoord, koppel ze samen met één dubbele punt, base64 de uitkomst, en stuur hem mee als Basic plus een spatie plus de gepakte string in de Authorization-header. In Kotlin:

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

Waarom hier Base64 en niet iets sterks? Omdat een header-waarde één drukbaar token moet zijn, en Base64 dat garandeert. De eerlijke waarschuwing: Base64 is encodering, geen versleuteling. Elke client kan YWxpY2U6czNjcjN0 in één stap terugbrengen naar alice:s3cr3t, daarom hoort Basic-authenticatie alleen op TLS-verbindingen, bij voorkeur met token-credentials in plaats van menselijke wachtwoorden. Parse je zo'n header, dan split je op het dubbele punt exact één keer, want het wachtwoord mag legaal dubbele punten bevatten.

Veldnotities: afbeeldingen en data-URLs

Data-URLs inlijnen binaire assets rechtstreeks in HTML, CSS en JSON, zodat de browser geen tweede request hoeft te maken. De vorm is een mediatype, een komma, het woord base64, nog een komma, en de gepakte bytes:

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=
}

De bytes hierboven zijn de eerste acht van een PNG-bestand, het magische getal dat elke decoder checkt. Waarom Base64 hier past: het payload moet een URL-safe tekentoken zijn binnen markup, en Base64 is de enige breed ondersteunde binaire-naar-tekst met een stabiele grammatica. De valkuil is de grootte. Een logo van 300 kilobyte wordt zo'n 400 kilobyte markup, en elke extra kilobyte wordt betaald bij elke paginaweergave die hem bevat. Data-URLs zijn een prachtig gereedschap voor iconen, avatars en kleine sprites; ze zijn een vreselijk gereedschap voor video, en zelfs een matig gereedschap voor een grote foto. Meet voordat je inlijnt.

Veldnotities: e-mailbijlagen

SMTP is een tekstprotocol dat ouder is dan elk begrip van binaire data, dus elke bijlage in elke e-mail die je ooit hebt ontvangen is Base64, omgewikkeld op 76 tekens, verklaard met een Content-Transfer-Encoding: base64-header. Een minimale MIME-part met een kleine binaire bijlage eruit, met het door Kotlin gegenereerde lichaamsveld ingevuld voor een 5-byte-%PDF--header:

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--

(Het lichaam JVBERi0= is de base64 van de vijf bytes %PDF-; een echt rapport zou zich over veel regels van 76 tekens wikkelen.) De Kotlin-kant is één regel wanneer je de bytes van het bestand hebt:

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

De valkuilen zijn kanaaldiscipline. Gebruik voor het lichaam Mime, niet Default, want een strikte MIME-parser verwacht de omwikkeling, en een simpele Default-regel van 10.000 tekens wordt door sommige transporten afgewezen of verkrapt. Houd het hoofdlettergebruik in de Content-Transfer-Encoding-regel exact base64, en onthoud dat de omwikkeling deel uitmaakt van het formaat: niet-omgewikkelde uitvoer en omgewikkelde uitvoer zijn verschillende representaties van dezelfde bytes, en de parser aan de andere kant moet weten welke hij eet.

Veldnotities: JSON-API's en uploads

Wanneer een API binaire data in een JSON-document wil, is de conventie een string-veld met base64, en dat is een van de meest handige patronen in het ecosysteem, omdat JSON al een plek voor tekst heeft. Met kotlinx.serialization is de heen-en-weertrip soepel:

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=="}
}

Waarom hier Base64: JSON heeft geen binair type, dus het payload moet tekst zijn, en Base64 is de minst verrassende binaire grammatica die een API-gebruiker zonder documentatie zal herkennen. De valkuil is de schaal. De 4/3-toeslag wordt bij elke request en elke response betaald, en een upload van 10 megabyte wordt een JSON-string van 13,3 megabyte die je parser in het geheugen vast moet houden, ontsnappen en valideren. Voor grote bestanden is multipart/form-data of een binair lichaam bijna altijd het betere draadformaat; reserveer base64-in-JSON voor miniatuurtjes, iconen, handtekeningen en kleine blobs waar de handigheid de belasting opweegt.

Veldnotities: configuratie en de command line

De laatste twee patronen zijn de kleine die in elke codebase voorkomen. Configuratiewaarden, tokens, licentiesleutels, soms kleine geheimen reizen vaak als base64 via omgevingsvariabelen en properties-bestanden, omdat het transport alleen tekst is en de waarde aanhalingstekens of regeleinden kan bevatten. Ze teruglezen is dezelfde tweetapsdans omgekeerd: System.getenv of een properties-opslag, en dan decoderen. Op de command line is een bestand encoderen voor transport of inspectie een tienregelsprogramma:

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")
}

Gelopen op een bestand met de tien bytes hello file, schrijft het 16 tekens, aGVsbG8gZmlsZQ==. De valkuilen in beide gevallen zijn dezelfde twee: Base64 in config is geen kluis, de waarde staat op één stap van platte tekst en moet op de draad in ieder geval als een geheim worden behandeld, en een zelfgeschreven CLI-tool moet zijn alfabet doelbewust kiezen, want een gebruiker die je uitvoer in een URL pipt, heeft UrlSafe nodig, niet Default.

Wat kan er misgaan tijdens encoderen

Encoderen is vergevingsgezind over inhoud: elke reeks bytes is geldige invoer, dus is er geen "invalid symbol"-mislukking zoals decoders hebben. Wat wel een uitzondering gooit is de geometrie, en de meldingen zijn precies genoeg om nuttig te zijn:

SituatieUitzonderingMelding
endIndex voorbij het einde van de arrayIndexOutOfBoundsExceptionstartIndex: 0, endIndex: 100, size: 5
startIndex verder dan endIndexIllegalArgumentExceptionstartIndex: 3 > endIndex: 2
bestemmingsarray te klein voor encodeIntoByteArrayIndexOutOfBoundsExceptionThe destination array does not have enough capacity, destination offset: 0, destination size: 2, capacity needed: 8

Naast deze zitten twee Kotlin-specifieke valkuilen. De eerste is de klassieke int + String-fout: bytes.size + " bytes" compileert niet, want plus op een Int voegt geen strings samen; de interpolatievorm "${bytes.size} bytes" is de Kotlin-manier. De tweede is het charset-opzoeken, dat voor een naam die de JVM niet herkent een UnsupportedCharsetException gooit, zoals Charset.forName("utf-9"), dus een typefout in een charset-naam is een runtime-uitzondering, geen compileerfout, en die komt boven op de plek waar de encoder draait, niet waar de naam is getikt.

Valkuilen, Kotlin-stijl

De valkuilen hieronder zijn degenen die specifiek Kotlin-ontwikkelaars bijten die voor het eerst naar de standaardbibliotheek grijpen:

  • encodeToByteArray() laten beslissen over het charset voor je. Dat is altijd UTF-8, stilzwijgend, en een Latin-1- of UTF-16-bron pakt dan in bytes die de decoder niet terug kan lezen. Beslis het charset doelbewust, met toByteArray(charset) op de JVM wanneer het niet UTF-8 is.
  • Uit spiergeheugen naar java.util.Base64 grijpen. Deze getUrlEncoder() gebruikt standaard padding, wat de verkeerde vorm is voor JWTs, tenzij je .withoutPadding() onthoudt; de Kotlin-voorgedefinieerde instantie maakt de keuze expliciet aan beide kanten.
  • Omgewikkelde Mime- of Pem-uitvoer geven aan een éénregelige consumer. De CRLFs maken deel uit van de representatie en falen bij een strikte decoder die één regel verwacht; wikkel alleen wanneer het kanaal omwikkeling verwacht.
  • text.getBytes() schrijven op een Kotlin-string. De Java-methode is niet zichtbaar op kotlin.String; de inline toByteArray(charset)-extensie, aanwezig sinds Kotlin 1.0, is de vervanging.
  • Oude toolchains draaien. De Kotlin van het systeem op enkele distributies is nog steeds 1.3, wat voorafgaat aan de standaardbibliotheek-Base64 als geheel; de class heeft 1.8.20 nodig om te bestaan, 2.0.20 voor paddingbesturing en 2.2 om stabiel te zijn.
  • Base64 behandelen als een beveiligingslaag. Het is een transportencoding met een publieke, een-staps-omgekeerde operatie. Alles geheim moet versleuteld worden voordat het wordt ingepakt, nooit alleen ingepakt.

Goed kiezen: een snelle beslisgids

In twijfelgevallen wordt het besluit bijna altijd gemaakt door het kanaal, niet de inhoud. De korte versie:

  • Base64.Default voor API's, JSON, data-URLs en alles wat effectief één regel tekst is. Uitvoer met padding is de meest compatibele vorm op de draad.
  • Base64.UrlSafe met ABSENT-padding voor tokens, JWTs en alles wat in een URL-segment of een query-parameter belandt.
  • Base64.Mime voor e-maillichamen en bijlagen, waar regels van 76 tekens een harde eis van het formaat zijn.
  • Base64.Pem voor certificaten en privésleutels, waar regels van 64 tekens zijn wat elk PKI-gereedschap verwacht.

Daarna twee dwarsgekante gewoontes: maak het charset expliciet telkens de invoer tekst is, en hou een oogje in het veld op de 4/3-toeslag, zodat grote payloads een binair kanaal krijgen in plaats van een base64-kanaal.

De weg naar standaard

De weg door de standaardbibliotheek naar Base64 is recent genoeg dat je oudere Kotlin tegenkomt zonder hem. De class verscheen voor het eerst in Kotlin 1.8.20 in april 2023, gemarkeerd als experimenteel, met drie instanties en een oppervlak dat eenvoudiger was: encoderen gaf altijd padding, en er was geen manier om minder te vragen. Als je 1.8-tijd-code hebt gezien die = van het einde van een string haalt met removeSuffix, dan was dat het enige gereedschap van die tijd voor niet-ingevulde uitvoer, en het is een gewoonte die je nu beter kunt laten varen. Kotlin 2.2, uitgebracht in juni 2025, maakte de API stabiel en voegde het laatste onderdeel toe, de Pem-instantie. De PaddingOption-regelaar en withPadding waren al aangeland in de 2.0-lijn, in 2.0.20 om precies te zijn, de eerste eerstklassige manier om padding in beide richtingen te sturen. De streaminghelpers encodingWith en decodingWith blijven experimenteel en alleen voor de JVM, dat is hoe de standaardbibliotheek API's markeert waarvoor ze eerst meer veldervaring willen voordat die definitief vastliggen. Sinds de 2.4.0-lijn is de taal ook overgegaan op een ondersteuningsvenster van 18 maanden voor de standaardbibliotheek, dus een project dat vastgezet is op een 2.4.x-compiler, zoals de stabiele 2.4.10-release die op het moment van schrijven actueel is, krijgt de volledige Base64-API voor de levensduur van die ondersteuningscyclus.

Kleine wonderen

Een paar details die de class interessanter maken zodra je ze kent:

  • Base64.encode(bytes) zonder instantie werkt omdat Base64.Default op het companion-object is gedefinieerd; het companion is het standaardschema, dus zijn de suiker en de genamen vorm letterlijk hetzelfde object.
  • De encodeToAppendable-functie is builder-stijl: hij retourneert de bestemming-appendable, dus het gedocumenteerde patroon is de retourwaarde te negeren en door te gaan met je builder.
  • Padding vult nooit een volledige groep: een base64-string eindigt met nul, één of twee =-tekens, en als je het aantal padtekens telt, zie je precies hoeveel bytes de oorspronkelijke data overhad in de laatste groep van drie.
  • Pem is de jongste van de vier voorgedefinieerde instanties, aangeland in 2.2; de omwikkeling op 64 tekens is een PKI-conventie die ouder is dan de RFC 2045-regel waar hij naast staat.
  • Op de JVM delegeert de standaardbibliotheek bewust niet naar java.util.Base64; de twee implementaties zijn apart, wat het gedrag identiek houdt over platforms heen, tegen de prijs van een in een comment geplaatste optimalisatie die het Kotlin-team in de boom heeft gehouden voor een toekomst waarin de Java-API het toelaat.
  • Dezelfde 2.2-release die Base64 stabiliseerde, stabiliseerde ook HexFormat, de hex-formateringclass in kotlin.text die sinds Kotlin 1.9 experimenteel was, zodat tekstuele encodings op bytesniveau nu een vaste plek hebben in de standaardbibliotheek.

Afronding en waar je naartoe gaat

Base64 produceren in Kotlin is een korte lijst van doelbewuste keuzes: kies de voorgedefinieerde instantie op kanaal, beslis de padding doelbewust, houd het charset expliciet wanneer de invoer tekst is, en respecteer de 4/3-toeslag wanneer het payload groot is. Alles andere, bestanden, buffers, appendables, streams, is een dunne verpakking rond dezelfde vier instanties. De andere richting, die gepakte tekst terug nemen naar bytes, heeft zijn eigen striktheidsregels, zijn eigen mislukkingen en zijn eigen valkuilen, en het gerelateerde artikel op de zustersite behandelt Base64-decoderen in Kotlin in diepte.

Laatst bijgewerkt: 2026-10-06

Gerelateerd artikel: Base64-decodering in Kotlin: een complete gids