Start · Sprachen · JavaScript · Referenz · Blob.stream()

Blob.stream()

Methode

Gibt einen <code>ReadableStream</code> zurück, der den Inhalt des Blobs stückweise als <code>Uint8Array</code>-Teile liefert.

seit JavaScript Baseline: alle modernen Browser (seit 2019/2020), Kategorie: webapi

Signatur

Blob.prototype.stream()

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

Typ
ReadableStream<Uint8Array>
Beschreibung
Ein neuer 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));
15

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`);
});
log.txt: 120394 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
});
10000 -> 49

// 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 Sie tee().
  • 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 TextDecoderStream oder mit TextDecoder und { stream: true }, nicht Stück für Stück mit decode().
  • Reader freigeben: Nach getReader() ist der Stream gesperrt. Mit reader.releaseLock() heben Sie die Sperre auf, mit reader.cancel() brechen Sie das Lesen ab.
  • Asynchrone Iteration: for await...of über einen ReadableStream funktioniert in Safari erst seit neueren Versionen. Nehmen Sie für breite Kompatibilität die getReader()-Schleife.
  • Kompatibilität: Chrome 76+, Firefox 69+, Safari 14.1+, Edge 79+. In Node.js ist die Methode ab 16.5 über Blob aus node:buffer verfügbar und liefert einen Web-ReadableStream, keinen Node-Stream. Umwandeln lässt er sich mit Readable.fromWeb().
  • Bei kleinen Blobs sind text() oder arrayBuffer() einfacher und ähnlich schnell.