Signatur
Beschreibung
Die Methode stream() einer Blob-Instanz (und damit auch jeder File-Instanz) liefert einen ReadableStream. Beim Lesen gibt er die Bytes des Blobs nacheinander als Uint8Array-Stücke aus. Der Blob wird also nicht auf einmal in den Speicher geladen, sondern schrittweise verarbeitet.
Sinnvoll ist das vor allem bei großen Dateien, etwa wenn Nutzer mehrere Gigabyte über ein <input type="file"> auswählen. Anders als bei arrayBuffer() oder text() lassen sich die Daten fortlaufend verarbeiten: Bytes zählen, Prüfsummen berechnen, über pipeThrough() mit TextDecoderStream oder CompressionStream umwandeln oder als Request-Body weiterreichen.
Jeder Aufruf von stream() erzeugt einen neuen, unabhängigen Stream. Ein Stream kann nur einmal gelesen werden. Solange ein Reader aktiv ist, ist er gesperrt (locked).
Rückgabewert
ReadableStream, dessen Teile Uint8Array-Objekte mit den Rohdaten des Blobs sind. Wie groß die einzelnen Teile sind, legt die Implementierung fest.Beispiele
Blob stückweise mit einem Reader lesen
const blob = new Blob(['Hallo, ', 'Streams!'], { type: 'text/plain' });
const countBytes = async (b) => {
const reader = b.stream().getReader();
let total = 0;
while (true) {
const { done, value } = await reader.read();
if (done) break;
total += value.byteLength; // value ist ein Uint8Array
}
return total;
};
console.log(await countBytes(blob));
Große Textdatei zeilenweise verarbeiten (TextDecoderStream)
const input = document.querySelector('input[type=file]');
input.addEventListener('change', async () => {
const file = input.files[0];
const textStream = file.stream().pipeThrough(new TextDecoderStream());
let rest = '';
let lines = 0;
// Asynchrone Iteration über ReadableStream (moderne Browser, Node.js)
for await (const chunk of textStream) {
const parts = (rest + chunk).split('\n');
rest = parts.pop();
lines += parts.length;
}
if (rest) lines++;
console.log(`${file.name}: ${lines} Zeilen`);
});
Datei vor dem Upload mit gzip komprimieren
const compressBlob = async (blob) => {
const compressed = blob.stream().pipeThrough(new CompressionStream('gzip'));
return new Response(compressed).blob();
};
const original = new Blob(['a'.repeat(10000)], { type: 'text/plain' });
const gz = await compressBlob(original);
console.log(original.size, '->', gz.size);
await fetch('/upload', {
method: 'POST',
headers: { 'Content-Encoding': 'gzip' },
body: gz
});
// Wichtig · Fallstricke
- Einmal lesbar: Ein Stream lässt sich nur einmal konsumieren. Soll der Inhalt mehrfach gelesen werden, rufen Sie
stream()erneut auf oder verwenden Sietee(). - Die Größe der Teile ist nicht festgelegt: Verlassen Sie sich nicht auf eine bestimmte Chunk-Größe. Bei Text kann ein Mehrbyte-UTF-8-Zeichen auf zwei Teile verteilt sein. Dekodieren Sie deshalb mit
TextDecoderStreamoder mitTextDecoderund{ stream: true }, nicht Stück für Stück mitdecode(). - Reader freigeben: Nach
getReader()ist der Stream gesperrt. Mitreader.releaseLock()heben Sie die Sperre auf, mitreader.cancel()brechen Sie das Lesen ab. - Asynchrone Iteration:
for await...ofüber einenReadableStreamfunktioniert in Safari erst seit neueren Versionen. Nehmen Sie für breite Kompatibilität diegetReader()-Schleife. - Kompatibilität: Chrome 76+, Firefox 69+, Safari 14.1+, Edge 79+. In Node.js ist die Methode ab 16.5 über
Blobausnode:bufferverfügbar und liefert einen Web-ReadableStream, keinen Node-Stream. Umwandeln lässt er sich mitReadable.fromWeb(). - Bei kleinen Blobs sind
text()oderarrayBuffer()einfacher und ähnlich schnell.