Einen String kodieren und dekodieren
Dart-Strings sind intern UTF-16, wandeln Sie sie also vor dem Kodieren mit utf8.encode in UTF-8-Bytes um:
import 'dart:convert';
void main() {
final enc = base64Encode(utf8.encode('héllo wörld'));
print(enc); // aMOpbGxvIHfDtnJsZA==
print(utf8.decode(base64Decode(enc))); // héllo wörld
}
base64Encode(bytes) ist die Kurzform von base64.encode(bytes), und base64Decode(s) die von base64.decode(s). Sind die dekodierten Bytes kein UTF-8, wirft utf8.decode die Meldung FormatException: Invalid UTF-8 byte; mit allowMalformed: true erhalten Sie stattdessen Ersatzzeichen.
Dieselben beiden Aufrufe erzeugen einen HTTP-Basic-Auth-Header, zum Beispiel für package:http:
final headers = {'Authorization': 'Basic ${base64Encode(utf8.encode('user:pass'))}'};
// Authorization: Basic dXNlcjpwYXNz
Der Basic-Auth-Header-Generator zeigt denselben Wert für beliebige Zugangsdaten.
URL-sicheres Base64 und normalize()
base64Url ist ein zweiter Codec mit dem Alphabet -_. Beide Encoder schreiben immer Padding; entfernen Sie es, wenn Ihr Format keines will:
final d = utf8.encode('<<???>>');
print(base64Url.encode(d)); // PDw_Pz8-Pg==
print(base64Url.encode(d).replaceAll('=', '')); // PDw_Pz8-Pg
Beim Dekodieren ist Dart freundlicher als die meisten Sprachen. Beide Decoder akzeptieren beide Alphabete, verlangen aber korrektes Padding. normalize behebt das und wandelt außerdem das Alphabet um:
base64Url.normalize('PDw_Pz8-Pg'); // PDw_Pz8-Pg==
base64.normalize('PDw_Pz8-Pg'); // PDw/Pz8+Pg==
utf8.decode(base64Url.decode(base64Url.normalize('PDw_Pz8-Pg'))); // <<???>>
utf8.decode(base64Decode('PDw_Pz8-Pg==')); // <<???>>
normalize wirft außerdem eine FormatException, wenn die Eingabe kein gültiges Base64 ist, und taugt damit auch als Validator. JWT-Segmente sind Base64URL ohne Padding; siehe Base64 vs. Base64URL und Padding erklärt, oder fügen Sie eines in den JWT-Decoder ein.
Mit normalize lässt sich die Payload eines JWT in einer Zeile lesen:
const jwt = 'eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0In0.sig';
final payload = utf8.decode(base64Url.decode(base64Url.normalize(jwt.split('.')[1])));
print(payload); // {"sub":"1234"}
print(jsonDecode(payload)['sub']); // 1234
Das liest nur die Claims und prüft die Signatur nicht. Verlassen Sie sich auf dem Client also nie für die Autorisierung darauf.
Eine Datei kodieren und dekodieren
import 'dart:io';
final bytes = await File('hello.txt').readAsBytes();
print(base64Encode(bytes)); // aGVsbG8K
await File('copy.txt').writeAsBytes(base64Decode('aGVsbG8K'));
Große Dateien streamen
base64.encoder und base64.decoder sind Stream-Transformer, eine Datei lässt sich also Block für Block umwandeln:
// encode: bytes -> Base64 text -> ASCII bytes on disk
await File('big.bin')
.openRead()
.transform(base64.encoder)
.transform(ascii.encoder)
.pipe(File('big.b64').openWrite());
// decode: ASCII bytes -> String chunks -> bytes
await File('big.b64')
.openRead()
.transform(ascii.decoder)
.transform(base64.decoder)
.pipe(File('big.out').openWrite());
Die Transformer heben übrig gebliebene Bytes zwischen den Blöcken auf, die Blockgröße spielt also keine Rolle. In beiden Richtungen kam eine 300-KB-Testdatei Byte für Byte genauso heraus wie mit den Funktionen im Speicher.
Flutter: Bilder und Data-URIs
So zeigen Sie ein Base64-Bild an:
Image.memory(base64Decode(b64))
Um Base64 aus einem Asset oder einer ausgewählten Datei zu erzeugen, lesen Sie die Bytes und rufen base64Encode auf. Bei Data-URIs kümmert sich UriData um das Präfix:
UriData.parse('data:text/plain;base64,aGk=').contentAsBytes(); // [104, 105]
UriData.fromBytes(pngBytes, mimeType: 'image/png').toString(); // data:image/png;base64,...
Eine Data-URI direkt an base64Decode zu übergeben scheitert mit Invalid character (at character 5); gemeint ist der : nach data. Um zu sehen, was ein unbekannter String enthält, zeigt Base64 in Bild eine Vorschau im Browser.
Validierung und FormatException-Meldungen
Alle Dekodierfehler sind FormatException. toString() enthält die Meldung, die Eingabe und ein Caret unter der Problemstelle; e.message und e.offset liefern die Teile einzeln. Mit base64Decode:
| Eingabe | Meldung |
|---|---|
aGk | Invalid length, must be multiple of four (at character 4) |
a | Invalid length, must be multiple of four (at character 2) |
aGk=!! | Invalid padding character (at character 5) |
aGk== | Invalid padding character (at character 5) |
aGl= | Invalid encoding before padding (at character 4) |
"aGVs\nbG8K" | Invalid character (at character 5) |
In zwei Punkten ist Dart streng, wo viele Sprachen tolerant sind: Es lehnt Zeilenumbrüche ab (entfernen Sie sie bei MIME- oder PEM-Eingaben) und Padding-Bits ungleich null (aGl=). Eine Gültigkeitsprüfung:
bool isBase64(String s) {
try {
base64Decode(s);
return true;
} on FormatException {
return false;
}
}
Scheitert ein String und sagt die Meldung nicht genug, markiert der Base64-Validator das Problem; Häufige Base64-Fehler erklärt die Ursachen.
Fallstricke
codeUnitskodieren.base64Encode('é'.codeUnits)liefert6Q==(Latin-1, nicht UTF-8), und'✓'.codeUnitswirftArgumentError: Invalid argument (Not a byte value at index 0: 0x2713). Gehen Sie immer überutf8.encode.- Zeilenumbrüche aus anderen Systemen. MIME-Ausgaben aus E-Mails oder von
base64unter Linux enthalten\n; entfernen Sie Leerraum vorher mits.replaceAll(RegExp(r'\s'), ''). - URL-sichere Ausgabe von
base64Encodeerwarten. Es schreibt+und/. Für alles, was in eine URL kommt, verwenden Siebase64Url.encode. - Kein MIME-Umbruch. Die Codecs fügen nie Zeilenumbrüche ein. Teilen Sie bei Bedarf selbst in Zeilen zu 76 Zeichen.
Häufige Fragen
Wie zeige ich ein Base64-Bild in Flutter an?
Dekodieren Sie in Bytes und verwenden Sie Image.memory(base64Decode(b64)). Ist der String eine Data-URI, entfernen Sie zuerst alles bis zum Komma oder nutzen UriData.parse(uri).contentAsBytes().
Warum meldet base64Decode „Invalid length, must be multiple of four“?
Die Eingabe hat kein Padding, was für JWTs und URL-sichere Tokens typisch ist. Rufen Sie zuerst base64.normalize(s) oder base64Url.normalize(s) auf; das ergänzt die fehlenden =.
Akzeptiert base64Decode in Dart URL-sichere Eingaben?
Ja. Der Decoder akzeptiert sowohl +/ als auch -_, base64Decode('PDw_Pz8-Pg==') funktioniert also. Nur die Encoder unterscheiden sich: base64 schreibt +/, base64Url schreibt -_.